diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/Leetcode/array/3Sum/readme.md b/Leetcode/array/3Sum/readme.md index 046c76a..0906825 100644 --- a/Leetcode/array/3Sum/readme.md +++ b/Leetcode/array/3Sum/readme.md @@ -5,6 +5,8 @@ tags: Array, Two Pointers --- ## 题目原文 +[原文地址](https://leetcode.com/problems/3sum/description/) + Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: The solution set must not contain duplicate triplets. @@ -29,6 +31,7 @@ A solution set is: ## 解题思路 ### 网上分析1 + 题目分析: 1. 每一个答案数组triplet中的元素是要求升序排列的。 @@ -47,63 +50,109 @@ A solution set is: 归根结底, 其实这是two pointers的想法, 定位其中两个指针, 根据和的大小来移动另外一个。 解题中要 注意的就是一些细节问题。 好了, 上代码吧。 - + ### 网上分析2 -the key idea is the same as the TwoSum problem. When we fix the 1st number,the 2nd and 3rd number can be found following the same reasoning as TwoSum. -The only difference is that, the TwoSum problem of LEETCODE has a unique solution.However, in ThreeSum, we have multiple duplicate solutions that can be found. Most ofthe OLE errors happened here because you could've ended up with a solution with so manyduplicates. +这个题目核心思想与 TwoSum, 当第一个数字固定后, 第二个数字和第三个数字就可以采用和TwoSum问题差不多的方法. 不同的是 TwoSum 问题只有一个确定的解, 这个问题却可能有多个解 -The naive solution for the duplicates will be using the STL methods like below : +这个问题还有一点是要解决数组中可能有重复的元素造成重复解的问题, 直觉上的想法是用STL: +```c++ std::sort(res.begin(), res.end()); - res.erase(unique(res.begin(), res.end()), res.end()); +``` -But according to my submissions, this way will cause you double your time consumingalmostly. -A better approach is that, to jump over the number which has been scanned, no matter itis part of some solution or not. - -If the three numbers formed a solution, we can safely ignore all the duplicates of them. -We can do this to all the three numbers such that we can remove the duplicates. -Here's my AC C++ Code: +但根据提交的结果分析, 采用上面的方法耗时较长. 比较好的方法是在遍历数据的时候, 就剔除重复数据, 无论这个数据是否是可行解的一部分. ### 我的分析: 主要是先将原数组排序,并充分利用排序好的数组的特性。去除重复答案的方法是,先按index从小到大确定第一个元素,在按(bengin=index)++和(end)--的顺序确定第二个元素和第三个元素,当begin=begin+1是跳过,end同理,第一个元素的所有可能循环完成后,index++之前也要判断index是否等于index+1。总而言之就是利用排序号数组特性保证每个元素都各不相同。先确定答案中最小的数,防止答案中出现重复的组合 +具体思路: + +1. 先用`std::sort`将原数组按升序排列 +2. 基本思路是定位第一个元素, 然后用两个指针分别指向数组剩余部分的头部和尾部, 根据两个指针指向数字的和移动指针. + +## 加速的小技巧 + + if(target < 0) + { + break; + } + # 这个实用性不是很强 + if(num[back] < 0) + { + break; + } +## 容易错的地方 + +### 1. + +``` +while(front> threeSum(vector& nums) { std::sort(nums.begin(),nums.end()); - vector> res; - for(int i=0;i> res; + + for (int i=0; itarget) + if (sum>target) back--; else if(sum tri(3,0); - tri[0]=nums[i]; - tri[1]=nums[front]; - tri[2]=nums[back]; + vector tri={nums[i], nums[front], nums[back]}; res.push_back(tri); - - while(front) + +给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 + +**说明:** + +- 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 +- 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + +**示例:** + +``` +输入: +nums1 = [1,2,3,0,0,0], m = 3 +nums2 = [2,5,6], n = 3 + +输出: [1,2,2,3,5,6] +``` -You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively. ## 题目大意 nums1和nums2是两个排序好的数组,把两个数组合并放入nums1并排好序。 - ## 解题思路 + A和B都已经是排好序的数组, 我们只需要从后往前比较就可以了。 因为A有足够的空间容纳A + B, 我们使用游标i指向m + n - 1, 也就是最大数值存放的地方, 从后往前遍历A, B, 谁大就放到i这里, 同时递减i。 +## 注意事项 + +要注意num1或num2在移动过程中, 变为空数组后的情况 + +注意判断的逻辑顺序, 先判断两个数组是否为空,在不为空的条件下,再进行比较大小, 这样逻辑容易一些 +单元测试, 特殊情况: + +``` +[1] +1 +[] +0 +``` ## 代码 + ### [c++代码](./src/cpp/MergeSortedArray.cpp) ```c++ class Solution { diff --git a/Leetcode/array/Pascal'sTriangle/readme.md b/Leetcode/array/Pascal'sTriangle/readme.md index 8fe6993..d39f688 100644 --- a/Leetcode/array/Pascal'sTriangle/readme.md +++ b/Leetcode/array/Pascal'sTriangle/readme.md @@ -5,33 +5,122 @@ tags: Array --- ## 题目原文 -GGiven numRows, generate the first numRows of Pascal's triangle. -For example, given numRows = 5, -Return +[题目链接](https://leetcode-cn.com/problems/pascals-triangle/) - [ - [1], - [1,1], - [1,2,1], - [1,3,3,1], - [1,4,6,4,1] - ] +给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 +![img](https://upload.wikimedia.org/wikipedia/commons/0/0d/PascalTriangleAnimated2.gif) +在杨辉三角中,每个数是它左上方和右上方的数的和。 + +**示例:** + +``` +输入: 5 +输出: +[ + [1], + [1,1], + [1,2,1], + [1,3,3,1], + [1,4,6,4,1] +] +``` ## 题目大意 + 输入一个数字,输出相应阶数的帕斯卡三角。 ## 解题思路 + 要得到一个帕斯卡三角, 我们只需要找到规律即可。 第k层有k个元素 每层第一个以及最后一个元素值为1 对于第k( k > 2) 层, 第n( n > 1 && n < k) 个元素A[k][n], A[k][n] = A[k-1][n-1] + A[k-1][n] +## c++ 知识点 + +### vector resize和reserve区别 + +``` +void reserve (size_type n); +``` + +reserve函数用来给vector**预分配**存储区大小,即capacity的值 ,但是没有给这段内存进行初始化。reserve 的参数n是推荐预分配内存的大小,实际分配的可能等于或大于这个值,即n大于capacity的值,就会reallocate内存 capacity的值会大于或者等于n 。这样,当vector调用push_back函数使得size 超过原来的默认分配的capacity值时 避免了内存重分配开销。 + +需要注意的是:reserve 函数分配出来的内存空间,只是表示vector可以利用这部分内存,但vector不能有效地访问这些内存空间,访问的时候就会出现越界现象,导致程序崩溃。 + +``` +void resize (size_type n); +void resize (size_type n, value_type val); +``` + +resize函数**重新分配**大小,改变容器的大小,并且创建对象 + +当n小于当前size()值时候,vector首先会减少size()值 保存前n个元素,然后将超出n的元素删除(remove and destroy) + +当n大于当前size()值时候,vector会插入相应数量的元素 使得size()值达到n,并对这些元素进行初始化,如果调用上面的第二个resize函数,指定val,vector会用val来初始化这些新插入的元素 + +当n大于capacity()值的时候,会自动分配重新分配内存存储空间。 + +容器调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问。 + +而reserve()函数预分配出的空间没有被初始化,所以不可访问。 + + + +参考: [C++:vector中的resize()函数 VS reserve()函数](https://www.cnblogs.com/biyeymyhjob/archive/2013/05/11/3072893.html), [vector resize和reverse区别](https://blog.csdn.net/yockie/article/details/7992057) + +## python 知识点 + +### Python List append()方法 + +**描述** +append() 方法用于在列表末尾添加新的对象。 + +**语法** +append()方法语法: + +```python +list.append(obj) +``` + +**参数** +obj -- 添加到列表末尾的对象。 +**返回值** +该方法无返回值,但是会修改原来的列表。 + +### python中append和extend函数区别 + +append函数直接将object整体当作一个元素追加到列表中,而extend函数则是将可迭代对象中的元素逐个追加到列表中。 + +```python +In [1]: lt1=['A','B','C'] + ...: lt2=['D','E','F'] + ...: lt1.append(lt2)#将lt2整体当作一个元素追加到到lt1中 + ...: print(lt1) + ...: lt3=['A','B','C'] + ...: lt2=['D','E','F'] + ...: lt3.extend(lt2)#将lt2中每个元素逐个追加到t3中 + ...: print(lt3) + ...: +['A', 'B', 'C', ['D', 'E', 'F']] + +``` + +### 技巧 + +```python +if j in (0,i): + pas[i].append(1) +``` + + ## 代码 + ### [c++代码](./src/cpp/Pascal'sTriangle.cpp) ```c++ class Solution { diff --git a/Leetcode/array/Pascal'sTriangleII/img/readme.assets/PascalTriangleAnimated2.gif b/Leetcode/array/Pascal'sTriangleII/img/readme.assets/PascalTriangleAnimated2.gif new file mode 100644 index 0000000..c002af4 Binary files /dev/null and b/Leetcode/array/Pascal'sTriangleII/img/readme.assets/PascalTriangleAnimated2.gif differ diff --git a/Leetcode/array/Pascal'sTriangleII/readme.md b/Leetcode/array/Pascal'sTriangleII/readme.md index 5865f8f..16889c4 100644 --- a/Leetcode/array/Pascal'sTriangleII/readme.md +++ b/Leetcode/array/Pascal'sTriangleII/readme.md @@ -5,18 +5,32 @@ tags: Array --- ## 题目原文 -Given an index k, return the kth row of the Pascal's triangle. -For example, given k = 3, -Return [1,3,3,1]. +[题目链接](https://leetcode-cn.com/problems/pascals-triangle-ii/) + +给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。 + +![img](img/readme.assets/PascalTriangleAnimated2.gif) + +在杨辉三角中,每个数是它左上方和右上方的数的和。 + +**示例:** + +``` +输入: 3 +输出: [1,3,3,1] +``` + +进阶: + +你可以优化你的算法到 O(k) 空间复杂度吗? -Note: -Could you optimize your algorithm to use only O(k) extra space? ## 题目大意 -给出帕斯卡三角形第k层,注意这里的K从0开始计数 +给出帕斯卡三角形第k层,注意这里的K从0开始计数 ## 解题思路 + 要求空间复杂度为O(K),因此不能使用二维数据,应用一维数组滚动计算。 采用从后往前计算的策略 @@ -29,9 +43,19 @@ Could you optimize your algorithm to use only O(k) extra space? 那么我们计算A[4][3]的时候就会出现问题了, 因为这时候A[3][2]不是3, 而是4了。 -为了解决这个问题, 我们只能从后往前计算, 仍然是上面那个例子, 我们实现计算A[4][3] = A[3][2] + A[3] -[3], 也就是6, 我们将6直接覆盖到3这个位置, 但不会影响我们计算A[4][2], 因为A[4][2] = A[3][1] + A[3] -[2], 已经不会涉及到3这个位置了。 +为了解决这个问题, 我们只能从后往前计算, 仍然是上面那个例子, 我们实现计算A[4][3] = A[3][2] + A[3][3], 也就是6, 我们将6直接覆盖到3这个位置, 但不会影响我们计算A[4][2], 因为A[4][2] = A[3][1] + A[3][2], 已经不会涉及到3这个位置了。 + +## python 知识点 + +```python +old, result[j] = result[j], old + result[j]# 这里等号右边是原来的值, 等号右边是计算后的值 +``` + +python 列表生成式, 是Python内置的非常简单却强大的可以用来创建list的生成式, 常常用来代替循环 + +```python +result = [1] + [result[j - 1] + result[j] for j in xrange(1, i)] + [1] +``` @@ -57,12 +81,13 @@ public: ```python class Solution:         # @return a list of integers +# 这份代码采用的是从前向后的顺序计算, 为了解决从前向后计算当前位置数据被覆盖的问题, 使用old变量保存更新前的当前位置的值, 用于下次计算.         def getRow(self, rowIndex):                 result = [0] * (rowIndex + 1)                 for i in xrange(rowIndex + 1):                         old = result[0] = 1                         for j in xrange(1, i + 1): -                                old, result[j] = result[j], old + result[j] +                                old, result[j] = result[j], old + result[j]# 这里等号右边是原来的值, 等号右边是计算后的值                 return result @@ -73,7 +98,7 @@ class Solution2:         def getRow(self, rowIndex):                 result = [1]                 for i in range(1, rowIndex + 1): -                        result = [1] + [result[j - 1] + result[j] for j in xrange(1, i)] + [1] +                        result = [1] + [result[j - 1] + result[j] for j in xrange(1, i)] + [1]# 这里等式右边依旧是原始的值, 右面是计算后的值, 计算过程中,result改变的值不会在等号左面产生影响                 return result diff --git a/Leetcode/array/PlusOne/readme.md b/Leetcode/array/PlusOne/readme.md index b62c161..4db5fe4 100644 --- a/Leetcode/array/PlusOne/readme.md +++ b/Leetcode/array/PlusOne/readme.md @@ -5,11 +5,30 @@ tags: Array,Math --- ## 题目原文 -Given a non-negative integer represented as a non-empty array of digits, plus one to the integer. +[题目链接](https://leetcode-cn.com/problems/plus-one/) -You may assume the integer do not contain any leading zero, except the number 0 itself. -The digits are stored such that the most significant digit is at the head of the list. +给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 + +最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。 + +你可以假设除了整数 0 之外,这个整数不会以零开头。 + +**示例 1:** + +``` +输入: [1,2,3] +输出: [1,2,4] +解释: 输入数组表示数字 123。 +``` + +**示例 2:** + +``` +输入: [4,3,2,1] +输出: [4,3,2,2] +解释: 输入数组表示数字 4321。 +``` ## 题目大意 用vector保存一个数字,个位数在索引最大的位置,计算这个数字加1后的结果。 @@ -18,8 +37,73 @@ The digits are stored such that the most significant digit is at the head of the ## 解题思路 写的更通用一些,可以加0-9,sum表示某一位上的相加和,dig表示进位,值只能取0或1,某一位上相加后为sum%10。 +## 注意事项 + +虽然不判断输入数组是否为空, 程序依旧可以成功提交, 但是最好还是加上输入判断 + +## C++知识点 + +在vector的指定位置插入指定元素, 下面的例子是在int型vector的开始处插入数字1 + +```c++ +digits.insert(digits.begin(),1); +``` + +## python 代码知识点 + +### Python2和Python3中除法操作的不同 + +Python中除法有两种运算符:’/’和’//’ + +在Python 2.6中,’/’执行传统除法,如果操作数都是整数的话,执行截断的整数除法(即对于结果只保留整数部分),否则,执行浮点除法(保留余数);’//’执行Floor除法,与Python3.0一样,对于整数执行截断除法,浮点数执行浮点除法。 + +在Python 3.0中,’/’总是执行真除法,不管操作数的类型,都会返回包含任何余数的浮点结果;’//’执行Floor除法,截除掉余数并且针对整数操作数返回一个整数,如果有任何一个操作数是浮点数,则返回一个浮点数。 + +补充: + +Floor除法:效果等同于math模块中的floor函数: + +math.floor(x) :返回不大于x的整数 + +所以当运算数是负数时:结果会向下取整。 + +> 5//3#1.6666666666666667 +> 1 +> -5//3 +> -2 + +**使代码中除法部分支持两个python版本** +尽管 / 的行为在python2.6和python3.0中不同,我们仍然能够在自己的代码中支持这两个版本,如果你的程序依赖于截断整数除法,在pyton2.6和python3.0中都使用//。如果你的程序对于整数需要有余数的浮点数结果,使用浮点数,从而确保代码在python2.6中运行的时候/的一个操作数是浮点数 + +参考: [Python2和Python3中除法操作/的不同](https://www.jianshu.com/p/ba132cb399a1), [python3之数字(在实际应用中的数字--除法:传统除法、Floor除法和真除法)](https://blog.csdn.net/fhd001/article/details/6969864) + +### Python2和Python3中range()函数的不同 + +Python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表。它只是在迭代的情况下返回指定索引的值,但是它并不会在内存中真正产生一个列表对象,这样也是为了节约内存空间。 + +Python3 list() 函数是对象迭代器,可以把range()返回的可迭代对象转为一个列表,返回的变量类型为列表。 + +Python2 range() 函数返回的是列表。 + +xrange也是python2的内置函数,用于创造xrange对象用于迭代。 +在python3中,range()这种实现被移除了,保留了xrange()的实现,且将xrange()重新命名成range(), python3的range()在xrange()的基础上变的更强大了 + +参考: [Python3:range和xrange](https://blog.csdn.net/jasonLee_lijiaqi/article/details/78973204), [Python3 range() 函数用法](http://www.runoob.com/python3/python3-func-range.html) + +### reversed() + +reversed()是python内置函数, 返回序列seq的反向访问的迭代器(迭代器的意思是只能通过循环来输出)。参数可以是列表,元组,字符串,不改变原对象。 + +**python中sort,sorted,reverse,reversed的区**别 + +简单的说以上四个内置函数都是排序。 + +对于sort和reverse都是list列表的内置函数,一般不传参数,没有返回值,会改变原列表的值。 + +而sorted和reversed是python内置函数,需要传参数,参数可以是字符串,列表,字典,元组,不管传的参数是什么sorted返回的都是列表,reversed返回的都是迭代器,原参数的值不会发生改变。 ## 代码 + ### [c++代码](./src/cpp/PlusOne.cpp) ```c++ class Solution { @@ -43,7 +127,9 @@ private: ``` ### [python代码](./src/python/PlusOne.py) + ```python +# python2 代码 class Solution: def plusOne(self,digits): dig=1; @@ -56,4 +142,21 @@ class Solution: return digits if __name__=="__mian__": print Solution().plusOne([9,9,9,9]) + +# python3 代码 +class Solution: + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + return self.plusX(digits, 1) + def plusX(self, digits, dig): + for i in reversed(range(len(digits))): + sum=digits[i]+dig + dig=sum//10 + digits[i]=sum%10 + if dig: + digits=[1]+digits + return digits ``` diff --git a/Leetcode/array/PlusOne/src/python/PlusOne.py b/Leetcode/array/PlusOne/src/python/PlusOne.py index d4585e9..60328b8 100644 --- a/Leetcode/array/PlusOne/src/python/PlusOne.py +++ b/Leetcode/array/PlusOne/src/python/PlusOne.py @@ -1,3 +1,4 @@ +# python2 代码 class Solution: def plusOne(self,digits): dig=1; @@ -9,4 +10,21 @@ def plusOne(self,digits): digits=[1]+digits return digits if __name__=="__mian__": - print Solution().plusOne([9,9,9,9]) \ No newline at end of file + print Solution().plusOne([9,9,9,9]) + +# python3 代码 +class Solution: + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + return self.plusX(digits, 1) + def plusX(self, digits, dig): + for i in reversed(range(len(digits))): + sum=digits[i]+dig + dig=sum//10 + digits[i]=sum%10 + if dig: + digits=[1]+digits + return digits \ No newline at end of file diff --git a/Leetcode/array/RemoveDuplicatesFromSortedArray/readme.md b/Leetcode/array/RemoveDuplicatesFromSortedArray/readme.md index 8bddc6f..d4e852c 100644 --- a/Leetcode/array/RemoveDuplicatesFromSortedArray/readme.md +++ b/Leetcode/array/RemoveDuplicatesFromSortedArray/readme.md @@ -5,23 +5,80 @@ tags: Array,Two Pointers --- ## 题目原文 -Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. - -Do not allocate extra space for another array, you must do this in place with constant memory. - -For example, -Given input array nums = [1,1,2], - -Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length. +[题目连接](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/) + +给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + +不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + +**示例 1:** + +``` +给定数组 nums = [1,1,2], + +函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 + +你不需要考虑数组中超出新长度后面的元素。 +``` +**示例 2:** + +``` +给定 nums = [0,0,1,1,1,2,2,3,3,4], + +函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 + +你不需要考虑数组中超出新长度后面的元素。 +``` + +**说明:** + +为什么返回数值是整数,但输出的答案是数组呢? + +请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 + +你可以想象内部操作如下: + +``` +// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +int len = removeDuplicates(nums); + +// 在函数里修改输入数组对于调用者是可见的。 +// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +for (int i = 0; i < len; i++) { +    print(nums[i]); +} +``` + ## 题目大意 删除数组中重复的元素,返回删除重复元素数组的长度 要求不可新声明数组 ## 解题思路 + 遍历数组,有连个索引值,index索引不重复的元素,i索引所有元素,将i索引元素与index元素比较,不同则放入index索引元素后,index元素按索引值排列放在数组前面 +## 注意事项 + +判断输入数组是否为空 + +## C++ 知识点 + +vector是否为空判断: + +```c++ +vector &nums +nums.empty()// true为空 +``` + +vector的大小/数组长度 + +```c++ +nums.size() +``` + ## 代码 + ### [c++代码](./src/cpp/RemoveDuplicatesFromSortedArray.cpp) ```c++ diff --git a/Leetcode/array/RemoveDuplicatesFromSortedArrayII/readme.md b/Leetcode/array/RemoveDuplicatesFromSortedArrayII/readme.md index 3603d34..2b79454 100644 --- a/Leetcode/array/RemoveDuplicatesFromSortedArrayII/readme.md +++ b/Leetcode/array/RemoveDuplicatesFromSortedArrayII/readme.md @@ -5,15 +5,50 @@ tags: Array,Two Pointers --- ## 题目原文 -Follow up for "Remove Duplicates": +[题目链接](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/) -What if duplicates are allowed at most twice? -For example, +给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。 -Given sorted array nums = [1,1,1,2,2,3], +不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 -Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn't matter what you leave beyond the new length. +**示例 1:** +``` +给定 nums = [1,1,1,2,2,3], + +函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 + +你不需要考虑数组中超出新长度后面的元素。 +``` + +**示例 2:** + +``` +给定 nums = [0,0,1,1,1,1,2,3,3], + +函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 + +你不需要考虑数组中超出新长度后面的元素。 +``` + +**说明:** + +为什么返回数值是整数,但输出的答案是数组呢? + +请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 + +你可以想象内部操作如下: + +``` +// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +int len = removeDuplicates(nums); + +// 在函数里修改输入数组对于调用者是可见的。 +// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +for (int i = 0; i < len; i++) { +    print(nums[i]); +} +``` ## 题目大意 删除数组中重复的元素,但允许重复两次,返回删除重复元素后数组的长度, @@ -22,13 +57,48 @@ Your function should return length = 5, with the first five elements of nums  ## 解题思路 加一个变量统计重复次数 +## 注意事项 + +判断输入数组的长度是否为空 + +在重复两次的时候也要进行交换, 即代码中的 +``` + else{ + temp++; + if (temp& nums) { - if (nums.size()<2) + if (nums.size()==0) return nums.size(); int i=0,last=2; for (int index=1,temp=0;index& nums) { - if (nums.size()<2) + if (nums.size()==0) return nums.size(); int i=0,last=2; for (int index=1,temp=0;index) -Given nums = [2, 7, 11, 15], target = 9, -Because nums[0] + nums[1] = 2 + 7 = 9, -return [0, 1]. +给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 -UPDATE (2016/2/13): +你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + +**示例:** + +``` +给定 nums = [2, 7, 11, 15], target = 9 + +因为 nums[0] + nums[1] = 2 + 7 = 9 +所以返回 [0, 1] +``` -The return format had been changed to zero-based indices. Please read the above updated description carefully. ## 题目大意 + n这道题目的意思是给定一个数组和一个值, 让求出这个数组中两个值的和等于这个给定值的坐 标。 输出是有要求的, 1, 坐标较小的放在前面, 较大的放在后面。 2, 这俩坐标从0开始计数。 +需要注意的是, 整数数组中的元素是没有排序好的. + ## 解题思路 第一步: 我们要分析题意, 其中有三个关键点: 1. 求出来的坐标值要按序排列。 @@ -34,7 +41,6 @@ n这道题目的意思是给定一个数组和一个值, 让求出这个数组 2. 因为有且只有一组答案符合要求, 所以这大大的降低了这道题目的难度, 也就是说, 我们只要找到符 合条件的两个数, 存入结果, 直接终止程序, 返回答案即可。 - 这道题不是很难, 是leetcode最开始的题目, 要求很明确, 很直接, 如果我们用两个for循环, O(n2)的时间复杂度去求解的话, 很容易计算出来, 但这明显不是面试官需要的答案。 brute force只有在你 不知道如何优化题目的时候, 将就的给出的一个解法。 。 那么我们能不能用O(n)的时间复杂度去解这道题 @@ -43,9 +49,94 @@ O(n2)的时间复杂度去求解的话, 很容易计算出来, 但这明显 对于stack和queue, 除了pop外, 查找的时间复杂度也是O(n)。 明显不是我们所需要的, 那么什么数据结构 的查找时间复杂度小呢?很显然是 hash_map, 查找的时间复杂度理想情况下是O(1)。 +这道题的解题思路想到了用hash map, 就比较好办了. hash map中, 其键值为输入数组的元素, hash map的元素为输入数组的索引. 从头遍历输入数组的数据nums[i], 如果hash map 中没有target-nums[i], 则将i存入哈希表, nums[i]为键值. 若果有, 则先返回hash[target-nums[i]], 再返回i, 因为输入数组按照从小到大的顺序排列, 较小的元素先被遍历, 会被存入哈希表. + +## C++ 知识点 + +### C++ STL之哈希表 | unordered_map + +C++ STL中,哈希表对应的容器是`unordered_map`(since C++ 11)。 根据C++ 11标准的推荐,用`unordered_map`代替`hash_map`。 + +**为什么要使用unordered_map代替hash_map?** + +- 因为标准化的推进,unordered_map原来属于boost分支和std::tr1中,而hash_map属于非标准容器。 +- 另外,使用之后,感觉速度和hash_map差不多,但是支持string做key,也可以使用复杂的对象作为key。 +- gxx需要添加编译选项:--std=gnu++0x或者--std=c++0x + +**与map的区别** +STL中,map对应的数据结构是红黑树。红黑树是一种近似于平衡的二叉查找树,里面的数据是有序的。在红黑树上做查找操作的时间复杂度为 O(logN)。而unordered_map对应 哈希表,哈希表的特点就是查找效率高,时间复杂度为常数级别 O(1), 而额外空间复杂度则要高出许多。所以对于需要高效率查询的情况,使用unordered_map容器。而如果对内存大小比较敏感或者数据存储要求有序的话,则可以用map容器。 + +**成员函数** + +| 操作 | 说明 | +| ------------- | ------------------------------------------------------------ | +| operator= | 赋值操作 | +| empty() | 判断容器是否为空 | +| size() | 返回容器存储元素数量 | +| max_size() | 返回容器最大存储容量 | +| begin() | 返回一个前向迭代器,指向第一个元素的位置 | +| end() | 返回一个迭代器,指向最后一个元素的下一个位置 | +| cbegin() | 返回一个逆向迭代器,指向逆序第一个元素的位置 | +| cend() | 返回一个逆序迭代器,指向逆序最后一个元素的下一个位置 | +| operator[] | 根据键值直接存取元素,若键值不存在,则插入之 | +| at() | 同上,不过不会插入新的键值,而是抛出out_of_range异常 | +| find() | 根据键值进行查找,找到返回所在迭代器,否则返回end迭代器 | +| count() | 统计key值在unordered_map中出现的次数。实际上,c++ unordered_map不允许有重复的key。因此,如果key存在,则count返回1,如果不存在,则count返回0 | +| equal_range() | 返回键值相等的区间,找到返回迭代器对,值均为参数键值对应的迭代器;找不到返回两个end | +| emplace() | 构造键值对,并插入容器内 | +| insert() | 插入键值对,支持拷贝插入,区间插入 | +| erase() | 移除元素,可传迭代器参数,键值参数,迭代器区间参数 | +| clear() | 清除容器内所有元素 | +| swap() | 交换两个容器内的元素 | + +### python 知识点 + +### 字典 + +字典是另一种可变容器模型,且可存储任意类型对象。 + +字典的每个键值(key=>value)对用冒号(**:**)分割,每个对之间用逗号(**,**)分割,整个字典包括在花括号(**{})**中 ,格式如下所示: + +``` +d = {key1 : value1, key2 : value2 } +``` + +键必须是唯一的,但值则不必。 +值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。 + +一个简单的字典实例: + +``` +dict = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'} +``` + +也可如此创建字典: + +``` +dict1 = { 'abc': 456 }; +dict2 = { 'abc': 123, 98.6: 37 }; +``` + +**迭代** + +1. 只对键的遍历 + +```python +d = {'name1' : 'pythontab', 'name2' : '.', 'name3' : 'com'} +for key in d: + print (key, ' value : ', d[key]) +``` + +2. 对键和值都进行遍历 + +``` python +for key, value in d.items(): + print (key, ' value : ', value) +``` + +**字典键的特性** -## 代码 ### [c++代码](./src/cpp/TwoSum.cpp) ```c++ class Solution { @@ -68,6 +159,7 @@ public: ``` ### [python代码](./src/python/TwoSum.py) + ```python class Solution(object): def twoSum(self,nums,target): diff --git a/readme.md b/readme.md index dd46758..b76da4f 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,9 @@ tags: 目录 这篇博客是我平时刷Leetcode,剑指offer题目和牛客网上的招聘题目等的代码、思路。代码和思路都保存在[我的github](https://github.com/Richard-coder/Programming-Practice/tree/master)上,我对于每一道题都尽量做到c++和python都进行实现。在解题的过程中会参考一些资料,难以面面俱到的写出参考信息,如若侵权,请联系删除。 代码思路的github连接:https://github.com/Richard-coder/Programming-Practice/tree/master + ## Leetcode + | 题号 | 题目&&题解 | c++ | python | 难度| | ---- | ---- | ---- | ---- | ---- | | 26 | [Remove Duplicates from Sorted Array](./Leetcode/array/RemoveDuplicatesFromSortedArray/readme.md) | [c++](./Leetcode/array/RemoveDuplicatesFromSortedArray/src/cpp/RemoveDuplicatesFromSortedArray.cpp) | | easy | @@ -20,25 +22,80 @@ tags: 目录 | 15 | [3Sum](./Leetcode/array/3Sum/readme.md) | [c++](./Leetcode/array/3Sum/src/cpp/3Sum.cpp) | [python](./Leetcode/array/3Sum/src/python/3Sum.py) | medium | ## 牛客网2017笔试题合集 + | 公司 | 题目&&题解 | c++ | python | | ---- | ---- | ---- | ---- | | 网易 | [合唱团](./牛客网2017笔试题合集/合唱团/readme.md) | [c++](./牛客网2017笔试题合集/合唱团/src/cpp/合唱团.cpp) | [python](./牛客网2017笔试题合集/合唱团/src/python/合唱团.py) | ## 剑指offer + +由于最近时间比较紧张, 部分题目的思路采用copy他人博客加自己总结的形式, 并且没有写python的代码, 有时间后会完善思路总结, 并补上Python的额代码. + | 考察点 | 题目&&题解 | c++ | python | | ---- | ---- | ---- | ---- | -| 数组 | [二维数组中的查找](./剑指offer/二维数组中的查找/readme.md) | [c++](./剑指offer/二维数组中的查找/src/cpp/二维数组中的查找.cpp) | [python](./剑指offer/二维数组中的查找/src/python/二维数组中的查找.py) | -| 字符串 | [替换空格](./剑指offer/替换空格/readme.md) | [c++](./剑指offer/替换空格/src/cpp/替换空格.cpp) | [python](./剑指offer/替换空格/src/python/替换空格.py) | -| 链表 | [从尾到头打印链表](./剑指offer/从尾到头打印链表/readme.md) | [c++](./剑指offer/从尾到头打印链表/src/cpp/从尾到头打印链表.cpp) | [python](./剑指offer/从尾到头打印链表/src/python/从尾到头打印链表.py) | -| 二叉树 | [重建二叉树](./剑指offer/重建二叉树/readme.md) | [c++](./剑指offer/重建二叉树/src/cpp/重建二叉树.cpp) | [python](./剑指offer/重建二叉树/src/python/重建二叉树.py) -| 栈 队列 | [用两个栈实现队列](./剑指offer/用两个栈实现队列/readme.md) | [c++](./剑指offer/用两个栈实现队列/src/cpp/用两个栈实现队列.cpp) | [python](./剑指offer/用两个栈实现队列/src/python/用两个栈实现队列.py) -| 二分查找 | [旋转数组的最小数字](./剑指offer/旋转数组的最小数字/readme.md) | [c++](./剑指offer/旋转数组的最小数字/src/cpp/旋转数组的最小数字.cpp) | [python](./剑指offer/旋转数组的最小数字/src/python/旋转数组的最小数字.py) -| 递归 | [斐波那契数列](./剑指offer/斐波那契数列/readme.md) | [c++](./剑指offer/斐波那契数列/src/cpp/斐波那契数列.cpp) | [python](./剑指offer/斐波那契数列/src/python/斐波那契数列.py) -| 位运算 | [二进制中1的个数](./剑指offer/二进制中1的个数/readme.md) | [c++](./剑指offer/二进制中1的个数/src/cpp/二进制中1的个数.cpp) | [python](./剑指offer/二进制中1的个数/src/python/二进制中1的个数.py) +| 数组 | [003-数组中重复的数字](./剑指offer/003-数组中重复的数字/readme.md) | [c++](./剑指offer/003-数组中重复的数字/src/cpp/003-数组中重复的数字.cpp) |[python](./剑指offer/003-数组中重复的数字/src/python/003-数组中重复的数字.py) | +| 数组 | [004-二维数组中的查找](./剑指offer/004-二维数组中的查找/readme.md) | [c++](./剑指offer/004-二维数组中的查找/src/cpp/004-二维数组中的查找.cpp) | [python](./剑指offer/003-二维数组中的查找/src/python/004-二维数组中的查找.py) | +| 字符串 | [005-替换空格](./剑指offer/005-替换空格/readme.md) | [c++](./剑指offer/005-替换空格/src/cpp/005-替换空格.cpp) | [python](./剑指offer/005-替换空格/src/python/005-替换空格.py) | +| 链表 | [006-从尾到头打印链表](./剑指offer/006-从尾到头打印链表/readme.md) | [c++](./剑指offer/006-从尾到头打印链表/src/cpp/006-从尾到头打印链表.cpp) | [python](./剑指offer/006-从尾到头打印链表/src/python/006-从尾到头打印链表.py) | +| 二叉树 | [007-重建二叉树](./剑指offer/006-重建二叉树/readme.md) | [c++](./剑指offer/007-重建二叉树/src/cpp/007-重建二叉树.cpp) | [python](./剑指offer/007-重建二叉树/src/python/007-重建二叉树.py) | +| 二叉树 | [008-二叉树的下一个结点](./剑指offer/008-二叉树的下一个结点/readme.md) | [c++](./剑指offer/008-二叉树的下一个结点/src/cpp/008-二叉树的下一个结点.cpp) | [python](./剑指offer/008-二叉树的下一个结点/src/python/008-二叉树的下一个结点.py) | +| 栈 队列 | [009-用两个栈实现队列](./剑指offer/009-用两个栈实现队列/readme.md) | [c++](./剑指offer/009-用两个栈实现队列/src/cpp/009-用两个栈实现队列.cpp) | [python](./剑指offer/009-用两个栈实现队列/src/python/009-用两个栈实现队列.py) | +| 递归 | [010-斐波那契数列](./剑指offer/010-斐波那契数列/readme.md) | [c++](./剑指offer/010-斐波那契数列/src/cpp/010-斐波那契数列.cpp) | [python](./剑指offer/010-斐波那契数列/src/python/010-斐波那契数列.py) | +| 二分查找 | [011-旋转数组的最小数字](./剑指offer/011-旋转数组的最小数字/readme.md) | [c++](./剑指offer/011-旋转数组的最小数字/src/cpp/011-旋转数组的最小数字.cpp) | [python](./剑指offer/011-旋转数组的最小数字/src/python/011-旋转数组的最小数字.py) | +| 回溯法 DFS | [012-矩阵中的路径](./剑指offer/012-矩阵中的路径/readme.md) | [c++](./剑指offer/012-矩阵中的路径/src/cpp/012-矩阵中的路径.cpp) | [python](./剑指offer/012-矩阵中的路径/src/python/012-矩阵中的路径.py) | +| 回溯法 DFS | [013-机器人的运动范围](./剑指offer/013-机器人的运动范围/readme.md) | [c++](./剑指offer/013-机器人的运动范围/src/cpp/013-机器人的运动范围.cpp) | [python](./剑指offer/013-机器人的运动范围/src/python/013-机器人的运动范围.py) | +| 动态规划 贪心算法 | [014-剪绳子](./剑指offer/014-剪绳子/readme.md) | [c++](./剑指offer/014-剪绳子/src/cpp/014-剪绳子.cpp) | [python](./剑指offer/014-剪绳子/src/python/014-剪绳子.py) | +| 位运算 | [015-二进制中1的个数](./剑指offer/015-二进制中1的个数/readme.md) | [c++](./剑指offer/015-二进制中1的个数/src/cpp/015-二进制中1的个数.cpp) | [python](./剑指offer/015-二进制中1的个数/src/python/015-二进制中1的个数.py) | +| 快速求幂算法 | [016-数值的整数次方](./剑指offer/016-数值的整数次方/readme.md) | [c++](./剑指offer/016-数值的整数次方/src/cpp/016-数值的整数次方.cpp) | [python](./剑指offer/016-数值的整数次方/src/python/016-数值的整数次方.py) | +| 链表 | [018_01-在O(1)时间删除链表结点](./剑指offer/018_01-在O(1)时间删除链表结点/readme.md) | [c++](./剑指offer/018_01-在O(1)时间删除链表结点/src/cpp/018_01-在O(1)时间删除链表结点.cpp) | [python](./剑指offer/018_01-在O(1)时间删除链表结点/src/python/018_01-在O(1)时间删除链表结点.py) | +| 链表 | [018_02-在O(1)时间删除链表结点](./剑指offer/018_02-在O(1)时间删除链表结点/readme.md) | [c++](./剑指offer/018_02-在O(1)时间删除链表结点/src/cpp/018_02-在O(1)时间删除链表结点.cpp) | [python](./剑指offer/018_02-在O(1)时间删除链表结点/src/python/018_02-在O(1)时间删除链表结点.py) | +| 递归 | [019-正则表达式匹配](./剑指offer/019-正则表达式匹配/readme.md) | [c++](./剑指offer/019-正则表达式匹配/src/cpp/019-正则表达式匹配.cpp) | [python](./剑指offer/019-正则表达式匹配/src/python/019-正则表达式匹配.py) | +| 字符串 | [020-表示数值的字符串](./剑指offer/020-表示数值的字符串/readme.md) | [c++](./剑指offer/020-表示数值的字符串/src/cpp/020-表示数值的字符串.cpp) | [python](./剑指offer/020-表示数值的字符串/src/python/020-表示数值的字符串.py) | +| 两指针 稳定排序 | [021-调整数组顺序使奇数位于偶数前面](./剑指offer/021-调整数组顺序使奇数位于偶数前面/readme.md) | [c++](./剑指offer/021-调整数组顺序使奇数位于偶数前面/src/cpp/021-调整数组顺序使奇数位于偶数前面.cpp) | [python](./剑指offer/021-调整数组顺序使奇数位于偶数前面/src/python/021-调整数组顺序使奇数位于偶数前面.py) | +| 两指针 | [022-链表中倒数第k个结点](./剑指offer/022-链表中倒数第k个结点/readme.md) | [c++](./剑指offer/022-链表中倒数第k个结点/src/cpp/022-链表中倒数第k个结点.cpp) | [python](./剑指offer/022-链表中倒数第k个结点/src/python/022-链表中倒数第k个结点.py) | +| 两指针 | [023-链表中环的入口结点](./剑指offer/023-链表中环的入口结点/readme.md) | [c++](./剑指offer/023-链表中环的入口结点/src/cpp/023-链表中环的入口结点.cpp) | [python](./剑指offer/023-链表中环的入口结点/src/python/023-链表中环的入口结点.py) | +| 链表 | [024-反转链表](./剑指offer/024-反转链表/readme.md) | [c++](./剑指offer/024-反转链表/src/cpp/024-反转链表.cpp) | [python](./剑指offer/024-反转链表/src/python/024-反转链表.py) | +| 链表 递归 | [025-合并两个排序的链表](./剑指offer/025-合并两个排序的链表/readme.md) | [c++](./剑指offer/025-合并两个排序的链表/src/cpp/025-合并两个排序的链表.cpp) | [python](./剑指offer/025-合并两个排序的链表/src/python/025-合并两个排序的链表.py) | +| 二叉树 递归 | [026-树的子结构](./剑指offer/026-树的子结构/readme.md) | [c++](./剑指offer/026-树的子结构/src/cpp/026-树的子结构.cpp) | [python](./剑指offer/026-树的子结构/src/python/026-树的子结构.py) | +| 二叉树 递归 遍历 | [027-二叉树的镜像](./剑指offer/027-二叉树的镜像/readme.md) | [c++](./剑指offer/027-二叉树的镜像/src/cpp/027-二叉树的镜像.cpp) | [python](./剑指offer/027-二叉树的镜像/src/python/027-二叉树的镜像.py) | +| 二叉树 递归 遍历 | [028-对称的二叉树](./剑指offer/028-对称的二叉树/readme.md) | [c++](./剑指offer/028-对称的二叉树/src/cpp/028-对称的二叉树.cpp) | [python](./剑指offer/028-对称的二叉树/src/python/028-对称的二叉树.py) | +| 边界条件 | [029-顺时针打印矩阵](./剑指offer/029-顺时针打印矩阵/readme.md) | [c++](./剑指offer/029-顺时针打印矩阵/src/cpp/029-顺时针打印矩阵.cpp) | [python](./剑指offer/029-顺时针打印矩阵/src/python/029-顺时针打印矩阵.py) | +| 栈 | [030-包含min函数的栈](./剑指offer/030-包含min函数的栈/readme.md) | [c++](./剑指offer/030-包含min函数的栈/src/cpp/030-包含min函数的栈.cpp) | [python](./剑指offer/030-包含min函数的栈/src/python/030-包含min函数的栈.py) | +| 栈 | [ 031-栈的压入弹出序列](./剑指offer/ 031-栈的压入弹出序列/readme.md) | [c++](./剑指offer/ 031-栈的压入弹出序列/src/cpp/ 031-栈的压入弹出序列.cpp) | [python](./剑指offer/ 031-栈的压入弹出序列/src/python/ 031-栈的压入弹出序列.py) | +| 层次遍历 二叉树 | [032_01-从上往下打印二叉树](./剑指offer/032_01-从上往下打印二叉树/readme.md) | [c++](./剑指offer/032_01-从上往下打印二叉树/src/cpp/032_01-从上往下打印二叉树.cpp) | [python](./剑指offer/032_01-从上往下打印二叉树/src/python/032_01-从上往下打印二叉树.py) | +| 层次遍历 二叉树 | [032_02-把二叉树打印成多行](./剑指offer/032_02-把二叉树打印成多行/readme.md) | [c++](./剑指offer/032_02-把二叉树打印成多行/src/cpp/032_02-把二叉树打印成多行.cpp) | [python](./剑指offer/032_02-把二叉树打印成多行/src/python/032_02-把二叉树打印成多行.py) | +| 层次遍历 二叉树 | [032_03-按之字形顺序打印二叉树](./剑指offer/032_03-按之字形顺序打印二叉树/readme.md) | [c++](./剑指offer/032_03-按之字形顺序打印二叉树/src/cpp/032_03-按之字形顺序打印二叉树.cpp) | [python](./剑指offer/032_03-按之字形顺序打印二叉树/src/python/032_03-按之字形顺序打印二叉树.py) | +| 递归 二叉搜索树 | [033-二叉搜索树的后序遍历序列](./剑指offer/033-二叉搜索树的后序遍历序列/readme.md) | [c++](./剑指offer/033-二叉搜索树的后序遍历序列/src/cpp/033-二叉搜索树的后序遍历序列.cpp) | [python](./剑指offer/033-二叉搜索树的后序遍历序列/src/python/033-二叉搜索树的后序遍历序列.py) | +| 二叉树 前序遍历 | [034-二叉树中和为某一值的路径](./剑指offer/034-二叉树中和为某一值的路径/readme.md) | [c++](./剑指offer/034-二叉树中和为某一值的路径/src/cpp/034-二叉树中和为某一值的路径.cpp) | [python](./剑指offer/034-二叉树中和为某一值的路径/src/python/034-二叉树中和为某一值的路径.py) | +| 链表 | [035-复杂链表的复制](./剑指offer/035-复杂链表的复制/readme.md) | [c++](./剑指offer/035-复杂链表的复制/src/cpp/035-复杂链表的复制.cpp) | [python](./剑指offer/035-复杂链表的复制/src/python/035-复杂链表的复制.py) | +| 二叉搜索树 中序遍历 | [036-二叉搜索树与双向链表](./剑指offer/036-二叉搜索树与双向链表/readme.md) | [c++](./剑指offer/036-二叉搜索树与双向链表/src/cpp/036-二叉搜索树与双向链表.cpp) | [python](./剑指offer/036-二叉搜索树与双向链表/src/python/036-二叉搜索树与双向链表.py) | +| 二叉搜索树 前序遍历 | [037-序列化二叉树](./剑指offer/037-序列化二叉树/readme.md) | [c++](./剑指offer/037-序列化二叉树/src/cpp/037-序列化二叉树.cpp) | [python](./剑指offer/037-序列化二叉树/src/python/037-序列化二叉树.py) | +| 全排列 | [038_01-字符串的排列](./剑指offer/038_01-字符串的排列/readme.md) | [c++](./剑指offer/038_01-字符串的排列/src/cpp/038_01-字符串的排列.cpp) | [python](./剑指offer/038_01-字符串的排列/src/python/038_01-字符串的排列.py) | +| 全组合 | [038_02-全组合-不含重复元素](./剑指offer/038_02-全组合-不含重复元素/readme.md) | [c++](./剑指offer/038_02-全组合-不含重复元素/src/cpp/038_02-全组合-不含重复元素.cpp) | [python](./剑指offer/038_02-全组合-不含重复元素/src/python/038_02-全组合-不含重复元素.py) | +| 全组合 | [038_03-全组合-含重复元素](./剑指offer/038_03-全组合-含重复元素/readme.md) | [c++](./剑指offer/038_03-全组合-含重复元素/src/cpp/038_03-全组合-含重复元素.cpp) | [python](./剑指offer/0038_03-全组合-含重复元素/src/python/038_03-全组合-含重复元素.py) | +| 全排列 | [038_04-对面和相等的正方体](./剑指offer/038_04-对面和相等的正方体/readme.md) | [c++](./剑指offer/038_04-对面和相等的正方体/src/cpp/038_04-对面和相等的正方体.cpp) | [python](./剑指offer/038_04-对面和相等的正方体/src/python/038_04-对面和相等的正方体.py) | +| 全排列 | [038_05-N皇后](./剑指offer/038_05-N皇后/readme.md) | [c++](./剑指offer/038_05-N皇后/src/cpp/038_05-N皇后.cpp) | [python](./剑指offer/038_05-N皇后/src/python/038_05-N皇后.py) | +| 数组 | [039-数组中出现次数超过一半的数字](./剑指offer/039-数组中出现次数超过一半的数字/readme.md) | [c++](./剑指offer/039-数组中出现次数超过一半的数字/src/cpp/039-数组中出现次数超过一半的数字.cpp) | [python](./剑指offer/039-数组中出现次数超过一半的数字/src/python/039-数组中出现次数超过一半的数字.py) | +| 数组 | [040-最小的K个数](./剑指offer/040-最小的K个数/readme.md) | [c++](./剑指offer/040-最小的K个数/src/cpp/040-最小的K个数.cpp) | [python](./剑指offer/040-最小的K个数/src/python/040-最小的K个数.py) | +| 最大堆 最小堆 | [041-数据流中的中位数](./剑指offer/041-数据流中的中位数/readme.md) | [c++](./剑指offer/041-数据流中的中位数/src/cpp/041-数据流中的中位数.cpp) | [python](./剑指offer/041-数据流中的中位数/src/python/041-数据流中的中位数.py) | +| 动态规划 | [042-连续子数组的最大和](./剑指offer/042-连续子数组的最大和/readme.md) | [c++](./剑指offer/042-连续子数组的最大和/src/cpp/042-连续子数组的最大和.cpp) | [python](./剑指offer/042-连续子数组的最大和/src/python/042-连续子数组的最大和.py) | +| 递归 | [043-从1到n整数中1出现的次数](./剑指offer/043-从1到n整数中1出现的次数/readme.md) | [c++](./剑指offer/043-从1到n整数中1出现的次数/src/cpp/043-从1到n整数中1出现的次数.cpp) | [python](./剑指offer/043-从1到n整数中1出现的次数/src/python/043-从1到n整数中1出现的次数.py) | +| 找规律 | [044-数字序列中某一位的数字](./剑指offer/044-数字序列中某一位的数字/readme.md) | [c++](./剑指offer/044-数字序列中某一位的数字/src/cpp/044-数字序列中某一位的数字.cpp) | [python](./剑指offer/044-数字序列中某一位的数字/src/python/044-数字序列中某一位的数字.py) | +| 排序 | [045-把数组排成最小的数](./剑指offer/045-把数组排成最小的数/readme.md) | [c++](./剑指offer/045-把数组排成最小的数/src/cpp/045-把数组排成最小的数.cpp) | [python](./剑指offer/045-把数组排成最小的数/src/python/045-把数组排成最小的数.py) | +| 递归 | [046-把数字翻译成字符串](./剑指offer/046-把数字翻译成字符串/readme.md) | [c++](./剑指offer/046-把数字翻译成字符串/src/cpp/046-把数字翻译成字符串.cpp) | [python](./剑指offer/046-把数字翻译成字符串/src/python/046-把数字翻译成字符串.py) | +| 动态规划 | [047-礼物的最大价值](./剑指offer/047-礼物的最大价值/readme.md) | [c++](./剑指offer/047-礼物的最大价值/src/cpp/047-礼物的最大价值.cpp) | [python](./剑指offer/047-礼物的最大价值/src/python/047-礼物的最大价值.py) | +| 动态规划 | [048-最长不含重复字符的子字符串](./剑指offer/048-最长不含重复字符的子字符串/readme.md) | [c++](./剑指offer/048-最长不含重复字符的子字符串/src/cpp/048-最长不含重复字符的子字符串.cpp) | [python](./剑指offer/048-最长不含重复字符的子字符串/src/python/048-最长不含重复字符的子字符串.py) | +| 空间换时间 | [049-丑数](./剑指offer/049-丑数/readme.md) | [c++](./剑指offer/049-丑数/src/cpp/049-丑数.cpp) | [python](./剑指offer/049-丑数/src/python/049-丑数.py) | +| 哈希表 | [050_01-第一个只出现一次的字符](./剑指offer/050_01-第一个只出现一次的字符/readme.md) | [c++](./剑指offer/050_01-第一个只出现一次的字符/src/cpp/050_01-第一个只出现一次的字符.cpp) | [python](./剑指offer/050_01-第一个只出现一次的字符/src/python/050_01-第一个只出现一次的字符.py) | +| 哈希表 | [050_02-字符流中第一个只出现一次的字符](./剑指offer/050_02-字符流中第一个只出现一次的字符/readme.md) | [c++](./剑指offer/050_02-字符流中第一个只出现一次的字符/src/cpp/050_02-字符流中第一个只出现一次的字符.cpp) | [python](./剑指offer/050_02-字符流中第一个只出现一次的字符/src/python/050_02-字符流中第一个只出现一次的字符.py) | +| 归并排序 | [051-数组中的逆序对](./剑指offer/051-数组中的逆序对/readme.md) | [c++](./剑指offer/051-数组中的逆序对/src/cpp/051-数组中的逆序对.cpp) | [python](./剑指offer/051-数组中的逆序对/src/python/051-数组中的逆序对.py) | +| 链表 两指针 | [051-数组中的逆序对](./剑指offer/051-数组中的逆序对/readme.md) | [c++](./剑指offer/052-两个链表的第一个公共结点/src/cpp/052-两个链表的第一个公共结点.cpp) | [python](./剑指offer/052-两个链表的第一个公共结点/src/python/052-两个链表的第一个公共结点.py) | + ## 经典算法&&数据结构 + | 考察点 | 题目&&题解 | c++ | python | | ---- | ---- | ---- | ---- | -| 排序 | [快速排序](./经典算法&&数据结构/快速排序/readme.md) | [c++](./经典算法&&数据结构/快速排序/src/cpp/快速排序.cpp) | [python](./经典算法&&数据结构/快速排序/src/python/快速排序.py) +| 排序 | [快速排序](./经典算法&&数据结构/快速排序/readme.md) | [c++](./经典算法&&数据结构/快速排序/src/cpp/快速排序.cpp) | [python](./经典算法&&数据结构/快速排序/src/python/快速排序.py) | @@ -48,4 +105,5 @@ tags: 目录 2. [LeetCode题解](https://github.com/soulmachine/leetcode) 3. [剑指Offer——名企面试官精讲典型编程题](https://github.com/gatieme/CodingInterviews) 4. [牛客网](https://www.nowcoder.com/9087476) - 5. [AlgorithmsByPython](https://github.com/Jack-Lee-Hiter/AlgorithmsByPython) \ No newline at end of file + 5. [AlgorithmsByPython](https://github.com/Jack-Lee-Hiter/AlgorithmsByPython) + diff --git "a/\345\211\221\346\214\207offer/001-/readme.md" "b/\345\211\221\346\214\207offer/001-/readme.md" new file mode 100644 index 0000000..dd5150c --- /dev/null +++ "b/\345\211\221\346\214\207offer/001-/readme.md" @@ -0,0 +1,29 @@ +# 003-数组中重复的数字 + +tags: 数组 + +--- + +## 题目原文 + +[牛客网链接]() + + + +## 解题思路 + + + +## 代码 + +### [c++代码](./src/cpp/003-数组中重复的数字.cpp) + +```c++ + +``` + +### [python代码](./src/python/003-数组中重复的数字.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/001-/src/cpp/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.cpp" "b/\345\211\221\346\214\207offer/001-/src/cpp/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.cpp" new file mode 100644 index 0000000..e69de29 diff --git "a/\345\211\221\346\214\207offer/001-/src/python/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.py" "b/\345\211\221\346\214\207offer/001-/src/python/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/001-/src/python/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227/readme.md" "b/\345\211\221\346\214\207offer/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227/readme.md" new file mode 100644 index 0000000..dd7aee5 --- /dev/null +++ "b/\345\211\221\346\214\207offer/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227/readme.md" @@ -0,0 +1,169 @@ +# 003-数组中重复的数字 + +tags: 数组 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=3) + +在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。 + +**样例输入** + +> 2, 3, 1, 0, 2, 5, 3 +> +> 2, 1, 3, 1, 4 + +**样例输出** + +> 2 +> +> 1 + +## 解题思路 + +### 一般解法 + +简单方法是把输入数组排序, 从排序好的数组中找到重复数字很容易.排序一个长度为$n$的数组需要$O(nlogn)$的时间 + +还可以用哈希表, 从头到尾扫描数组中的每个数字, 每扫描到一个数字的时候都可以用$O(1)$的时间来判断哈希表里是否已经包含了该数字.如果哈希表里没有这个数字, 就把它加入哈希表, 如果哈希表中已经存在该数字, 那么就找到一个重复的数字. 这种解法时间复杂度是$O(n)$, 但提高时间效率的代价是以一个大小为$O(n)$的哈希表为代价. + +### 较好解法 + +这种解法充分利用数组中的数字都在$0 \sim n-1$ 的条件, 可以达到$O(n)$的时间复杂度和$O(1)$的空间复杂度 + +我们考虑如果每个数字都置出现一次,那么此时是最完美的,每一个下标i对应元素numbers[i],也就是说我们对于数组中的每个元素numbers[i]都把它放在自己应该在的位置上numbers[numbers[i]]上, 如果我们发现有两个元素想往同一个位置上放的时候,说明此元素必然重复 + +即如下的过程 + +1. 如果numbers[i] == i, 那么我们认为number[i]这个元素是在自己的位置上的 +2. 否则的话, numbers[i]这个元素就应该在numbers[numbers[i]]这个位置上, 于是我们交换numbers[i]和numbers[numbers[i]] +3. 重复操作1, 直到number[i]== i, 则继续操作下一个位置的元素, 或者numbers[i] == numbers[numbers[i],元素重复 + +需要注意的是这种解法的前提是数组中的数字在0~n-1内. + +## 代码 + +### [c++代码](./src/cpp/003-数组中重复的数字.cpp) + +```c++ +class Solution { +public: + // Parameters: + // numbers: an array of integers + // length: the length of array numbers + // duplication: (Output) the duplicated number in the array number + // Return value: true if the input is valid, and there are some duplications in the array number + // otherwise false + bool duplicate(int numbers[], int length, int* duplication) { + if (numbers==nullptr) return false; + // 这种解法的前提是数组中的数字在0~n-1内 + for(int i=0;ilength-1){ + return false; + } + } + + for(int i=0;i>1)+start; + int count=countRange(numbers,length,start, middle); + if(end==start){ + if(count>1) + return start; + else + return -1; + } + if(count>(middle-start+1)) + end=middle; + else + start=middle+1; + } + return -1; +} + +int countRange(const int* numbers,int length, int start, int end){ + if (numbers==nullptr) return 0; + int count=0; + for(int i=0;i=start&&numbers[i]<=end) + count++; + } + + return count; +} +``` + + + diff --git "a/\345\211\221\346\214\207offer/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227/src/cpp/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.cpp" "b/\345\211\221\346\214\207offer/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227/src/cpp/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.cpp" new file mode 100644 index 0000000..071d93f --- /dev/null +++ "b/\345\211\221\346\214\207offer/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227/src/cpp/003-\346\225\260\347\273\204\344\270\255\351\207\215\345\244\215\347\232\204\346\225\260\345\255\227.cpp" @@ -0,0 +1,33 @@ +class Solution { +public: + // Parameters: + // numbers: an array of integers + // length: the length of array numbers + // duplication: (Output) the duplicated number in the array number + // Return value: true if the input is valid, and there are some duplications in the array number + // otherwise false + bool duplicate(int numbers[], int length, int* duplication) { + if (numbers==nullptr) return false; + // 这种解法的前提是数组中的数字在0~n-1内 + for(int i=0;ilength-1){ + return false; + } + } + + for(int i=0;i。 对于数组中的任何一个元素, 比它小的元素都在它的左方或者上方, 比它大的元素都在它的右边或者下方 -如果随意选择数组中的一个数字进行查找,会出现查找区域重叠的情况 +这道题我最开始的想法是当作一个二维版本的二分查找来做的,每次都与矩阵中间的数字作比较, 根据比较结果剔除一些候选区域. 但发现使用这种方式进行查找, 会有重叠的查找区域, 比如下图的深色阴影部分. ![重叠区域示意图][1]
重叠区域示意图
+所以可以考虑选取特殊位置的点进行比较, 比如右上角和左下角的点. 这两个位置的点的特点是, 所在行的最大值, 同时也是所在列的最小值(以右上角的点为例), 所以每次可以根据比较结果删除查找范围的一列或者一行, 而左上角和右下角的点则不可以, 因为这两个位置的点, 即是所在列的最小值, 又是所在行的最小值(以左上角的点为例), 不能根据比较结果删除查找范围的某一行或者某一列. 为了不重复的处理重叠的数据, 我们可以找几个特殊的起点,经过简单分析可以得到,可以从左下角或者右上角开始 @@ -24,28 +29,34 @@ tags: 查找 + 比他小的数必定在它的左侧,就往左找 + 比他大的数必定在它的下侧,就往下找 +## 注意 + +书里给的代码中输入array是二维数组, 而在牛客网上是vector >, 所以矩阵每行每列的长度不一定相等, 因此在判断边界条件时, 一定要用对应的行或列的长度 + ## 代码 -### [c++代码](./src/cpp/二维数组中的查找.cpp) + +### [c++代码](./src/cpp/004-二维数组中的查找.cpp) ```c++ class Solution { public: bool Find(int target, vector > array) { - bool find=false; - for(int row=0,col=array[row].size()-1;row < array.size()&&col>=0;){ - if (target==array[row][col]) - return find=true; - else if(array[row][col]>target) - col--; - else - row++; + if(array.empty()) return false; + for(int i=0,j=array[i].size()-1;i=0;){ + if(array[i][j]==target) + return true; + else if(array[i][j]>target) + j--; + else + i++; } - return find; + return false; } }; ``` -### [python代码](./src/python/二维数组中的查找.py) +### [python代码](./src/python/004-二维数组中的查找.py) + ```python # -*- coding:utf-8 -*- class Solution: @@ -76,4 +87,5 @@ while True: break ``` -[1]:./img/重叠区域示意图.png \ No newline at end of file +[1]:./img/重叠区域示意图.png + diff --git "a/\345\211\221\346\214\207offer/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/cpp/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.cpp" "b/\345\211\221\346\214\207offer/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/cpp/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.cpp" new file mode 100644 index 0000000..ce016c7 --- /dev/null +++ "b/\345\211\221\346\214\207offer/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/cpp/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.cpp" @@ -0,0 +1,15 @@ +class Solution { +public: + bool Find(int target, vector > array) { + if(array.empty()) return false; + for(int i=0,j=array[i].size()-1;i=0;){ + if(array[i][j]==target) + return true; + else if(array[i][j]>target) + j--; + else + i++; + } + return false; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/python/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" "b/\345\211\221\346\214\207offer/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/python/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/python/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" rename to "\345\211\221\346\214\207offer/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/python/004-\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.py" diff --git "a/\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/img/\344\273\216\345\220\216\345\220\221\345\211\215\346\233\277\346\215\242\347\251\272\346\240\274\350\277\207\347\250\213.png" "b/\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/img/\344\273\216\345\220\216\345\220\221\345\211\215\346\233\277\346\215\242\347\251\272\346\240\274\350\277\207\347\250\213.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/img/\344\273\216\345\220\216\345\220\221\345\211\215\346\233\277\346\215\242\347\251\272\346\240\274\350\277\207\347\250\213.png" rename to "\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/img/\344\273\216\345\220\216\345\220\221\345\211\215\346\233\277\346\215\242\347\251\272\346\240\274\350\277\207\347\250\213.png" diff --git "a/\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/img/\351\207\215\345\217\240\345\214\272\345\237\237\347\244\272\346\204\217\345\233\276.png" "b/\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/img/\351\207\215\345\217\240\345\214\272\345\237\237\347\244\272\346\204\217\345\233\276.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/img/\351\207\215\345\217\240\345\214\272\345\237\237\347\244\272\346\204\217\345\233\276.png" rename to "\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/img/\351\207\215\345\217\240\345\214\272\345\237\237\347\244\272\346\204\217\345\233\276.png" diff --git "a/\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/readme.md" "b/\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/readme.md" similarity index 94% rename from "\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/readme.md" rename to "\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/readme.md" index f2c0a36..9a1be24 100644 --- "a/\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/readme.md" +++ "b/\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/readme.md" @@ -1,10 +1,12 @@ -# 字符串 替换空格 +# 005-替换空格 tags: 字符串 --- ## 题目原文 +[牛客网链接](https://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=11155&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) + 请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 ## 解题思路 @@ -30,9 +32,8 @@ tags: 字符串 涉及到指针的问题,要避免越界或者访问空指针,所以要判断字符串是否为空 -![从后向前替换空格过程][1] +![从后向前替换空格过程](./img/从后向前替换空格过程.png)
从后向前替换空格过程
- ## 编程知识 ### python #### [python里快速创建指定大小的list的方法](https://bbs.pku.edu.cn/v2/post-read.php?bid=1360&threadid=14398267) @@ -143,4 +144,3 @@ class Solution: ``` -[1]:./img/从后向前替换空格过程.png \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/src/cpp/\346\233\277\346\215\242\347\251\272\346\240\274.cpp" "b/\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/src/cpp/\346\233\277\346\215\242\347\251\272\346\240\274.cpp" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/src/cpp/\346\233\277\346\215\242\347\251\272\346\240\274.cpp" rename to "\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/src/cpp/\346\233\277\346\215\242\347\251\272\346\240\274.cpp" diff --git "a/\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/src/python/\346\233\277\346\215\242\347\251\272\346\240\274.py" "b/\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/src/python/005-\346\233\277\346\215\242\347\251\272\346\240\274.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\233\277\346\215\242\347\251\272\346\240\274/src/python/\346\233\277\346\215\242\347\251\272\346\240\274.py" rename to "\345\211\221\346\214\207offer/005-\346\233\277\346\215\242\347\251\272\346\240\274/src/python/005-\346\233\277\346\215\242\347\251\272\346\240\274.py" diff --git "a/\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/readme.md" "b/\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/readme.md" new file mode 100644 index 0000000..915b050 --- /dev/null +++ "b/\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/readme.md" @@ -0,0 +1,212 @@ +# 链表 从尾到头打印链表 + +tags: 链表 + +--- + +## 题目原文 +[牛客网链接](https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tqId=11156&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) + +输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。 + +## 解题思路 +从头到尾遍历链表,将链表的值依次放入栈中,遍历完成后再依次从栈顶输出每个节点 + +因为递归的本质在于栈就够,因此也可以用递归完成本题。访问一个节点时,先递归输出其子节点,再输出其自身. 但是递归的方法在链表比较长的时候, 函数的调用层级会很深, 从而有可能导致函数调用栈溢出.显然用栈基于循环的方法鲁棒性高一些. + +## 代码 + +### [c++代码](./src/cpp/006-从尾到头打印链表.cpp) + +```c++ +/** +* struct ListNode { +* int val; +* struct ListNode *next; +* ListNode(int x) : +* val(x), next(NULL) { +* } +* }; +*/ +class Solution { +public: + //使用栈结构的方法 + vector printListFromTailToHead(ListNode* head) { + stack nodes;//由于链表结构简单,用一个辅助变量即可,可以不用栈 + + ListNode *pNode=head; + while(pNode!=NULL){ + nodes.push(pNode); + pNode=pNode->next; + } + //为了效率使用静态vector,使用静态vector后不能使用push_back + vector res(nodes.size()); + int i=0; + while(!nodes.empty()){ + pNode=nodes.top(); + res[i++]=pNode->val; + nodes.pop(); + } + return res; + } + //使用递归的方法 + vector res; + vector printListFromTailToHead2(ListNode* head){ + if(head!=NULL){ + printListFromTailToHead2(head->next); + res.push_back(head->val); + } + return res; + } +}; +``` + +### [python代码](./src/python/006-从尾到头打印链表.py) + +```python +# -*- coding:utf-8 -*- +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + # 返回从尾部到头部的列表值序列,例如[1,2,3] + def printListFromTailToHead2(self, listNode): + # write code here + if not listNode: + return [] + res=[] + head=listNode + while head: + res.insert(0,head.val) + head=head.next + return res + def printListFromTailToHead(self, listNode,res=None): + if res==None: + res=[] + if not listNode: + return [] + else: + self.printListFromTailToHead(listNode.next,res) + res.append(listNode.val) + return res +``` + +## c++ 知识点 + +### C++标准库之stack(各函数及其使用全) + +> [参考](https://www.cnblogs.com/shrimp-can/p/5283207.html) + +使用栈,要先包含头文件 : #include + +定义栈,以如下形式实现: stack s; 其中Type为数据类型(如 int,float,char等)。 + +栈的主要操作: + +``` +s.push(item); //将item压入栈顶 +s.pop(); //删除栈顶的元素,但不会返回 +s.top(); //返回栈顶的元素,但不会删除 +s.size(); //返回栈中元素的个数 +s.empty(); //检查栈是否为空,如果为空返回true,否则返回false +``` + +栈是后入先出的。成员函数有: + +1.**栈的声明** + +``` +std::deque mydeque (3,100); // deque with 3 elements +std::vector myvector (2,200); // vector with 2 elements +std::stack first; // empty stackstd::stack second (mydeque); // stack initialized to copy of deque +std::stack > third; // empty stack using vector +std::stack > fourth (myvector); +std::cout << "size of first: " << first.size() << '\n'; +std::cout << "size of second: " << second.size() << '\n'; +std::cout << "size of third: " << third.size() << '\n'; +std::cout << "size of fourth: " << fourth.size() << '\n';结果为:0 3 0 2 +``` + +2.bool **empty()** const + +判断栈是否为空 + +stack c; c.empty() + +3.size_type **size()** const + +返回栈中元素数量 + +c.size(); + +4.value_type& **top()**; + + const value_type &top() const; + +返回栈顶元素 + +c.top(); + +5.void **push(**const value_type& val) + +在栈顶插入一个元素 + +c.push(value); + +6.void **emplace**(args&& args); + +在栈顶增加一个元素 + +c.emplace(value) + +7.void **pop()** + +出栈,即删除栈顶元素 + +c.pop(); + +8.void **swap** (stack& x); + +交换两个栈中的内容 + +c.swap(d); + +9.与vector一样,重载了运算符:== != < <= > >= + +1. (1)==用于比较两个栈是否相等,首先判断大小是否相等,然后再通过operator ==判断元素之间是否相等,将会在第一个不相等的地方停止 +2. (2)!= 和==是相反的。只要大小不同或者有一个元素不一样就是不相等的 +3. (3),< ,从第一元素开始比较当发现大于或者等于时停止,如果一个栈是另一个栈的前缀,那么长的栈大。下同 + +**易混淆知识点** + +**push() 和 emplace() (C++11)** + +> push()函数和emplace()都是在栈这个容器的顶部插入一个新的元素。 +> push(),实际上是调用的底层容器的push_back()函数,新元素的值是push函数参数的一个拷贝。 +> emplace(),实际上是调用的底层容器的emplace_back()函数,新元素的值是在容器内部就地构造的,不需要移动或者拷贝。 +> stack的emplace也可以用在普通的基本类型上。 + +```cpp + +struct Node +{ + Node(int x) + :x(x){} + int x; +}; + +int main() +{ + stacks1; + s1.emplace(1); + s1.push(Node(2)); + + stacks2; + s2.emplace(1); //OK + return 0; +} +``` + +**栈没有clear或者erase函数,如果想要清空一个栈,需要循环的调用出栈函数。** \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/cpp/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.cpp" "b/\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/cpp/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.cpp" similarity index 100% rename from "\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/cpp/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.cpp" rename to "\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/cpp/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.cpp" diff --git "a/\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/python/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" "b/\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/python/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/python/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" rename to "\345\211\221\346\214\207offer/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/src/python/006-\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250.py" diff --git "a/\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/img/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206.png" "b/\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/img/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/img/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206.png" rename to "\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/img/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206.png" diff --git "a/\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/readme.md" "b/\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/readme.md" similarity index 53% rename from "\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/readme.md" rename to "\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/readme.md" index bb2c24b..f80cc78 100644 --- "a/\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/readme.md" +++ "b/\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/readme.md" @@ -1,10 +1,13 @@ -# 二叉树 重建二叉树 +# 007-重建二叉树 tags: 二叉树 --- ## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 ## 解题思路 @@ -19,7 +22,6 @@ tags: 二叉树 ![二叉树遍历][1]
二叉树遍历
- ### 解题 二叉树前序遍历的第一个节点即为根节点,在中序遍历中根据根节点的位置可以划分出左右子树,然后再前序遍历中找到左右子树。 在找到了左右子树的前序遍历和中序遍历后,进行递归即可。 @@ -27,7 +29,7 @@ tags: 二叉树 注意:这道题需要对输入进行判断,默认原二叉树节点的值不重复 ## 代码 -### [c++代码](./src/cpp/重建二叉树.cpp) +### [c++代码](./src/cpp/007-重建二叉树.cpp) ```c++ /** @@ -42,46 +44,64 @@ tags: 二叉树 class Solution { public: TreeNode* reConstructBinaryTree(vector pre,vector vin) { - //判断两个序列长度是否相等,不相等则出错 + // 判断输入是否合法 + if(pre.empty()||vin.empty()||pre.size()!=vin.size()) + throw std::logic_error("Invalid Input"); + return ReconstructCore(pre,vin); + } + TreeNode* ReconstructCore(vector pre,vector vin){ + // 两个序列长度不相等, 报错 if(pre.size()!=vin.size()) - return NULL; - int length = pre.size(); - //判断序列长度是否为0,为0是有可能是输入错误,也有可能是空的子树 - if (length==0) - return NULL; - int rootValue= pre[0]; - TreeNode *root=new TreeNode(rootValue); - - //找到中序遍历中根节点的位置 + throw std::logic_error("Invalid Input"); + // 输入序列长度为0, 空子树,返回空指针 + int length=pre.size(); + if(pre.size()==0) + return nullptr; + // 获取根节点的值,如果序列长度为1,说明此时根节点已经是叶子节点了, 返回根节点 + TreeNode* root=new TreeNode(pre[0]); + if(length==1){ + if(pre[0]==vin[0]) + return root; + else + throw std::logic_error("Invalid Input"); + } + // 在中序遍历中找到根节点的位置 int rootIndex=0; - for(;rootIndex=length) - return NULL; - int leftLenghth=rootIndex,rightLength=length-rootIndex-1; - vector preLeft(leftLenghth),preRight(rightLength);//长度为0时。则初始化为空的容器 - vector vinLeft(leftLenghth),vinRight(rightLength); - for (int i=0;i=length) + throw std::logic_error("Invalid Input"); + // 计算左右子树的值 + int leftLength=rootIndex, rightLength=length-1-rootIndex; + // 初始化左右子树两种遍历序列的容器,长度为0时。则初始化为空的容器 + vector preLeft(leftLength),preRight(rightLength); + vector vinLeft(leftLength),vinRight(rightLength); + for(int i=0;irootIndex){ + if(i>rootIndex) + { preRight[i-rootIndex-1]=pre[i]; vinRight[i-rootIndex-1]=vin[i]; } } - root->left=reConstructBinaryTree(preLeft,vinLeft); - root->right=reConstructBinaryTree(preRight,vinRight); + // 递归调用 + root->left=ReconstructCore(preLeft,vinLeft); + root->right=ReconstructCore(preRight,vinRight); return root; - - } + } }; ``` -### [python代码](./src/python/重建二叉树.py) + + +### [python代码](./src/python/007-重建二叉树.py) ```python # -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/cpp/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.cpp" "b/\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/cpp/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.cpp" similarity index 100% rename from "\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/cpp/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.cpp" rename to "\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/cpp/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.cpp" diff --git "a/\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/python/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" "b/\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/python/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/python/\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" rename to "\345\211\221\346\214\207offer/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221/src/python/007-\351\207\215\345\273\272\344\272\214\345\217\211\346\240\221.py" diff --git "a/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/img/readme.assets/7711710_1551248788315_suanfa6-9.png" "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/img/readme.assets/7711710_1551248788315_suanfa6-9.png" new file mode 100644 index 0000000..1f26d57 Binary files /dev/null and "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/img/readme.assets/7711710_1551248788315_suanfa6-9.png" differ diff --git "a/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/img/readme.assets/7711710_1551248788367_suanfa6-8.png" "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/img/readme.assets/7711710_1551248788367_suanfa6-8.png" new file mode 100644 index 0000000..a90201b Binary files /dev/null and "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/img/readme.assets/7711710_1551248788367_suanfa6-8.png" differ diff --git "a/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/readme.md" "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/readme.md" new file mode 100644 index 0000000..f8e8b08 --- /dev/null +++ "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/readme.md" @@ -0,0 +1,92 @@ +# 008-二叉树的下一个结点 + +tags: 二叉树 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e?tpId=13&tqId=11210&tPage=3&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 + +## 解题思路 + +> 参考: [我去个地方啊](https://www.nowcoder.com/questionTerminal/9023a0c988684a53960365b889ceaf5e) + +把每个节点看作一个根节点, 考虑其子树和父节点. + +中序排序的规则如下图所示 + +![image](img/readme.assets/7711710_1551248788367_suanfa6-8.png) + + + +我们从这个图上可以看到,找下一个节点是可以分为几种情况的。 + +**第一种情况:** + +> 就是一个节点有右子树。比如要求节点B的下一个节点,其实是找到它的右子树的最左孩子,就是G节点。 + +**第二种情况,就是一个节点没有右子树,此时又可以分为两种情况。** + +> - 2.1 对于G这个节点来说,没有右子节点了,它的父亲节点是E,G是E的左子节点,即E的左子节点是G,那么G的下一个节点就是E。 +> +> - 2.2 对于E这个节点来说,也没有右子节点,它的父亲节点是B,此时E是B的右子节点,根据实际情况来说,E的下一个节点绝对不是B,因为E是B的右子节点,根据中序遍历的规则,此时肯定是先遍历B再遍历E,所以B肯定在E的前面,而不是后面,所以我们还需要再往上找父亲节点,此时B的父亲节点为A,B为A的左子节点,此时根据实际情况,A就是我们要找的E的下一个节点。 + +对于第二种情况的两种情况可以合并为一种情况, 即对于一个没有右子节点的节点来说,只需要判断它有没有父节点并且是不是父节点的左子节点,是的话,就找到了,不是则要不断地向上找。如果一直找到根还是找不到,像节点F,那就返回null,因为实际上F节点就是中序遍历的最后一个节点,没有所谓的下一个节点了。 + + ![image](img/readme.assets/7711710_1551248788315_suanfa6-9.png) + + 总之,我们不关心当前节点的左子节点,因为它不在我们的考虑范围内,它必定出现在当前节点的前面。 + + 我们主要就是考虑有没有右子节点,或者没有右子节点的话就考虑父亲节点。有右子节点比较简单,一直找最左边的子节点即可。但是没有右子节点的时候,就需要去查询父亲节点了。 + +**注意** + +考虑输入节点是根节点或者最后一个节点等情况 + +## 代码 + +### [c++代码](./src/cpp/008-二叉树的下一个结点.cpp) + +```c++ +/* +struct TreeLinkNode { + int val; + struct TreeLinkNode *left; + struct TreeLinkNode *right; + struct TreeLinkNode *next; //parent + TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) { + + } +}; +*/ +class Solution { +public: + TreeLinkNode* GetNext(TreeLinkNode* pNode) + { + if(pNode==nullptr) return nullptr; + TreeLinkNode* pNext=nullptr; + if(pNode->right!=nullptr){ + pNode=pNode->right; + while(pNode->left!=nullptr) + pNode=pNode->left; + pNext=pNode; + } + // 我的写法将第二种情况的两小种情况合二为一, 并且可以完美处理输入节点为根节点,或者为最后一个节点的情况. + else{ + while(pNode->next!=nullptr&&pNode==pNode->next->right) + pNode=pNode->next; + pNext=pNode->next; + } + return pNext; + } +}; +``` + +### [python代码](./src/python/008-二叉树的下一个结点.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/src/cpp/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.cpp" "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/src/cpp/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.cpp" new file mode 100644 index 0000000..e460ea5 --- /dev/null +++ "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/src/cpp/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.cpp" @@ -0,0 +1,32 @@ +/* +struct TreeLinkNode { + int val; + struct TreeLinkNode *left; + struct TreeLinkNode *right; + struct TreeLinkNode *next; //parent + TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) { + + } +}; +*/ +class Solution { +public: + TreeLinkNode* GetNext(TreeLinkNode* pNode) + { + if(pNode==nullptr) return nullptr; + TreeLinkNode* pNext=nullptr; + if(pNode->right!=nullptr){ + pNode=pNode->right; + while(pNode->left!=nullptr) + pNode=pNode->left; + pNext=pNode; + } + // 我的写法将第二种情况的两小种情况合二为一, 并且可以完美处理输入节点为根节点,或者为最后一个节点的情况. + else{ + while(pNode->next!=nullptr&&pNode==pNode->next->right) + pNode=pNode->next; + pNext=pNode->next; + } + return pNext; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/src/python/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.py" "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/src/python/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271/src/python/008-\344\272\214\345\217\211\346\240\221\347\232\204\344\270\213\344\270\200\344\270\252\347\273\223\347\202\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\346\240\210\346\250\241\346\213\237\344\270\200\344\270\252\351\230\237\345\210\227\347\232\204\346\223\215\344\275\234.png" "b/\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\346\240\210\346\250\241\346\213\237\344\270\200\344\270\252\351\230\237\345\210\227\347\232\204\346\223\215\344\275\234.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\346\240\210\346\250\241\346\213\237\344\270\200\344\270\252\351\230\237\345\210\227\347\232\204\346\223\215\344\275\234.png" rename to "\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\346\240\210\346\250\241\346\213\237\344\270\200\344\270\252\351\230\237\345\210\227\347\232\204\346\223\215\344\275\234.png" diff --git "a/\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\351\230\237\345\210\227\346\250\241\346\213\237\344\270\200\344\270\252\346\240\210\347\232\204\346\223\215\344\275\234.png" "b/\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\351\230\237\345\210\227\346\250\241\346\213\237\344\270\200\344\270\252\346\240\210\347\232\204\346\223\215\344\275\234.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\351\230\237\345\210\227\346\250\241\346\213\237\344\270\200\344\270\252\346\240\210\347\232\204\346\223\215\344\275\234.png" rename to "\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/img/\347\224\250\344\270\244\344\270\252\351\230\237\345\210\227\346\250\241\346\213\237\344\270\200\344\270\252\346\240\210\347\232\204\346\223\215\344\275\234.png" diff --git "a/\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/readme.md" "b/\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/readme.md" similarity index 96% rename from "\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/readme.md" rename to "\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/readme.md" index 9e7d82a..8b97b45 100644 --- "a/\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/readme.md" +++ "b/\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/readme.md" @@ -1,10 +1,11 @@ -# 栈和队列 用两个栈实现队列 +# 009-用两个栈实现队列 tags: 栈 队列 --- ## 题目原文 + 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 ## 解题思路 @@ -23,7 +24,6 @@ tags: 栈 队列 ![用两个栈模拟一个队列的操作][1]
用两个栈模拟一个队列的操作
- ### 拓展 两个队列模拟一个栈 用两个队列实现栈,进栈出栈后,一定有一个队列空的,进栈直接压入非空队列,出栈是将除最后一个元素都压入空队列,然后弹出原非空栈的最后一个元素即可 @@ -31,7 +31,7 @@ tags: 栈 队列 ![用两个队列模拟一个栈的操作][2]
用两个队列模拟一个栈的操作
## 代码 -### [c++代码](./src/cpp/用两个栈实现队列.cpp) +### [c++代码](./src/cpp/009-用两个栈实现队列.cpp) ```c++ //两个栈实现队列,一个负责push,一个负责pop就好了 @@ -103,7 +103,7 @@ private: }; ``` -### [python代码](./src/python/用两个栈实现队列.py) +### [python代码](./src/python/009-用两个栈实现队列.py) ```python diff --git "a/\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/cpp/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.cpp" "b/\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/cpp/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.cpp" similarity index 100% rename from "\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/cpp/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.cpp" rename to "\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/cpp/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.cpp" diff --git "a/\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/python/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" "b/\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/python/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/python/\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" rename to "\345\211\221\346\214\207offer/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227/src/python/009-\347\224\250\344\270\244\344\270\252\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.py" diff --git "a/\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" "b/\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" rename to "\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" diff --git "a/\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/readme.md" "b/\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/readme.md" new file mode 100644 index 0000000..3bbba49 --- /dev/null +++ "b/\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/readme.md" @@ -0,0 +1,260 @@ +#010-斐波那契数列 + +tags: 递归 + +--- + +## 题目原文 +大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。 +n<=39 + +## 解题思路 +### 低效率不实用的方法 +斐波那契数列的求解方法最容易些想到的就是如下的递归形式 +```c++ +long long Fibonacci(unsigned int n){ + if (n<=0) + return 0; + + if (n==1) + return 1; + + return Fibonacci(n-1)+Fibonacci(n-2) +} +``` +上面的递归形式看起来很简单,但效率却很低,因为在递归的过程中存在着大量的重复计算。例如,计算f(10)的时候需要计算f(8)和f(9),在计算f(9)的时候又要计算一遍f(8),因此,计算的时间复杂度会随着n的增大而指数级增大。 + +### 改进方法 + +上面的方法问题在于递归的过程存在大量的重复计算,因此可以考虑在计算的过程中把计算结果保存下来,比如建立一个数组保存中间计算结果,但这也不是好的方法,因为耗费了额外的内存空间。 + +换种思路,先根据f(0)和f(1)计算出f(2),再依次计算出f(3),f(4),...,f(n),这种计算方法的空间复杂度是常数,时间复杂度是O(n) + +### 代码 +#### [c++代码](./src/cpp/010-斐波那契数列.cpp) + +```c++ +class Solution { +public: + int Fibonacci(int n) { + int result[2]={0,1}; + if (n<2) + return result[n]; + long long int f_zero=0, f_one=1,f_res=0; + int count=1; + while(count= 2: + for i in range(2, n+1): + tempArray[i%2] = tempArray[0] + tempArray[1] + return tempArray[n%2] +``` + +### 时间复杂度为$\Theta(logn)$但不是很实用的解法 +介绍解法之前先介绍下面的数学公式: + +$$\begin{bmatrix}f(n)&f(n-1)\\f(n-1)&f(n-2) \end{bmatrix}=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$$ + +这个公式可以用数学归纳法证明,有了这个公示后,原来的问题就变成了求矩阵$=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$,若果只是简单的从0开始循环计算,n次方需要n次计算,时间复杂度仍为$\Theta(n)$,与前面的方法相同,但可以考虑**乘方的如下性质** + +$$a^n=\begin{cases} a^{n/2}.a^{n/2} &\text{n为偶数} \\ a^{(n-1)/2}.a^{(n-1)/2}.a & \text{n为奇数} \end{cases}$$ + +但这种方法隐含的时间常数比较大(不是很懂),很少会有软件采用这种算法,另外这种算法实现复杂,有多个递归基,不适合面试。 + + +实现上面的方法时,需要定义一个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算,比较麻烦,可以将递归公式转换一下形式: + + +原理:观察:f(n)=f(n-1)+f(n-2)=2f(n-2)+f(n-3)=3f(n-3)+2f(n-4)=5f(n-4)+3f(n-5)=...=f(k).f(n-k+1)+f(k-1).f(n-k) + +若令n=2k,则有f(2k)=f(k).f(k+1)+f(k-1).f(k)=f(k).(f(k)+f(k-1))+f(k-1).f(k)=f(k)^2+2.f(k).f(k-1) + +若令n=2*k-1,则有f(2k-1)=f(k) * f(k) + f(k - 1) * f(k - 1) = f(k) ^ 2 + f(k - 1) ^ 2 + +**这种方法一般不会出现在笔试中, 但是利用乘方的性质将O(n)的计算降为O(log n)这种思想比较重要** + +### 拓展1 青蛙跳台阶 + +[牛客网链接](https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4?tpId=13&tqId=11161&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) + +题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。 + +通过题目的描述,可以很清晰地看到,这就是一个Fibonacci数列。 + +注意与`010-斐波那契数列`不同, `010-斐波那契数列`中f(0)为0, 这道题f(0)=1; 斐波那契数列的标准公式是f(0)=0 + +**c++代码** + +``` +class Solution { +public: + int jumpFloor(int number) { + int f1=1,f2=1; + int res; + if(number==0) return f1; + if(number==1) return f2; + for(int i=2;i<=number;i++){ + res=f1+f2; + f1=f2; + f2=res; + } + return res; + } +}; +``` + +### 拓展2 变态跳台阶 + +[牛客网链接](https://www.nowcoder.com/practice/22243d016f6b47f2a6928b4313c85387?tpId=13&tqId=11162&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) + + **题目描述** + +一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 + +#### 思路1 + +> [参考](https://www.nowcoder.com/questionTerminal/22243d016f6b47f2a6928b4313c85387) + + f(1) = 1 + + f(2) = f(2-1) + f(2-2) //f(2-2) 表示2阶一次跳2阶的次数。 + + f(3) = f(3-1) + f(3-2) + f(3-3) + + ... + + f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-(n-1)) + f(n-n) + +​ + + 说明: + + 1)这里的f(n) 代表的是n个台阶有一次1,2,...n阶的 跳法数。 + + 2)n = 1时,只有1种跳法,f(1) = 1 + + 3) n = 2时,会有两个跳得方式,一次1阶或者2阶,这回归到了问题(1) ,f(2) = f(2-1) + f(2-2) + + 4) n = 3时,会有三种跳得方式,1阶、2阶、3阶, + +​ 那么就是第一次跳出1阶后面剩下:f(3-1);第一次跳出2阶,剩下f(3-2);第一次3阶,那么剩下f(3-3) + +​ 因此结论是f(3) = f(3-1)+f(3-2)+f(3-3) + + 5) n = n时,会有n中跳的方式,1阶、2阶...n阶,得出结论: + +​ f(n) = f(n-1)+f(n-2)+...+f(n-(n-1)) + f(n-n) => f(0) + f(1) + f(2) + f(3) + ... + f(n-1) + +​ + + 6) 由以上已经是一种结论,但是为了简单,我们可以继续简化: + +​ f(n-1) = f(0) + f(1)+f(2)+f(3) + ... + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2) + +​ f(n) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2) + f(n-1) = f(n-1) + f(n-1) + +​ 可以得出: + +​ f(n) = 2*f(n-1) + +​ + + 7) 得出最终结论,在n阶台阶,一次有1、2、...n阶的跳的方式时,总得跳法为: + +$$f(n)=\begin{cases} 1 &\text{n=0}\\1 & \text{n=1}\\ +2*f(n-1) & \text{n>2}\end{cases}$$ + +**c++代码** + +``` +class Solution { +public: + int jumpFloorII(int number) { + int f1=1; + if(number==1||number==0) + return 1; + for(int i=2;i<=number;i++) + f1=2*f1; + + return f1; + } +}; +``` + +#### 思路2 + +> [参考](https://www.nowcoder.com/questionTerminal/22243d016f6b47f2a6928b4313c85387) + + 每个台阶可以看作一块木板,让青蛙跳上去,n个台阶就有n块木板,最后一块木板是青蛙到达的位子, 必须存在,其他 (n-1) 块木板可以任意选择是否存在,则每个木板有存在和不存在两种选择,(n-1) 块木板 就有 [2^(n-1)] 种跳法,可以直接得到结果。 + +其实我们所要求的序列为:0,1,2,4,8,16,…… +所以除了第一位外,其他位的数都是前一位的数去乘以2所得到的积 + +**c++代码** + +``` +class Solution { +public: + int jumpFloorII(int number) { + return 1<<--number; + } +}; +``` + + + +### 拓展3 铺瓷砖问题 + +[牛客网链接](https://www.nowcoder.com/practice/72a5a919508a4251859fb2cfb987a0e6?tpId=13&tqId=11163&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) + +我们可以用2x1的小矩形横着或者竖着取覆盖更大的矩阵,请问用8个2x1的小矩形取无重叠地覆盖一个2x8的大矩形,总共有多少种方法? + +![斐波那契数列拓展2][1] +
斐波那契数列拓展2
+记2x8的覆盖方法记为f(8),用第一个1x2的小矩形取覆大矩形的的最左边时有两个选择,竖着放或者横着放,竖着放的时候,覆盖方法为f(7),横着放的时候,比如在左上角,则左下角也只能在横着放一个小矩形,因此,横着放的时候覆盖方法为f(6),因此f(8)=f(7)+f(6),可以看出这仍然是斐波那契数列。 + +**c++代码** + +**注意** + +``` +class Solution { +public: + int rectCover(int number) { + if(number<=0) + return number; + if(number==1) return 1; + if(number==2) return 2; + int f1=1,f2=2; + int res; + for(int i=3;i<=number;i++){ + res=f1+f2; + f1=f2; + f2=res; + } + return res; + } +}; +``` + + + + +[1]:./img/斐波那契数列拓展2.png \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/cpp/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.cpp" "b/\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/cpp/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.cpp" similarity index 100% rename from "\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/cpp/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.cpp" rename to "\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/cpp/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.cpp" diff --git "a/\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/python/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" "b/\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/python/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/python/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" rename to "\345\211\221\346\214\207offer/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/python/010-\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.py" diff --git "a/\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/img/\346\237\245\346\211\276\346\227\213\350\275\254\346\225\260\347\273\204\346\234\200\345\260\217\346\225\260\345\255\227\350\277\207\347\250\213.png" "b/\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/img/\346\237\245\346\211\276\346\227\213\350\275\254\346\225\260\347\273\204\346\234\200\345\260\217\346\225\260\345\255\227\350\277\207\347\250\213.png" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/img/\346\237\245\346\211\276\346\227\213\350\275\254\346\225\260\347\273\204\346\234\200\345\260\217\346\225\260\345\255\227\350\277\207\347\250\213.png" rename to "\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/img/\346\237\245\346\211\276\346\227\213\350\275\254\346\225\260\347\273\204\346\234\200\345\260\217\346\225\260\345\255\227\350\277\207\347\250\213.png" diff --git "a/\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/readme.md" "b/\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/readme.md" similarity index 77% rename from "\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/readme.md" rename to "\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/readme.md" index c70fbbc..af12314 100644 --- "a/\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/readme.md" +++ "b/\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/readme.md" @@ -1,4 +1,4 @@ -#二分查找 旋转数组的最小数字 +# 011-旋转数组的最小数字 tags: 二分查找 @@ -23,11 +23,10 @@ tags: 二分查找 ![查找旋转数组最小数字过程][1]
查找旋转数组最小数字过程
- ### 特例 然而,上述思路只考虑了一般情况,没有考虑特例。 -(1) 当数组未发生旋转时:即将原数组前0个元素移动到后面,仍符合旋转数组的定义,但此时第一个元素小于或等于最后一个元素,且第一个元素就是最小值,此时直接返回第一个元素的值即可。 +(1) 当数组未发生旋转时:即将原数组前0个元素移动到后面,仍符合旋转数组的定义,但此时第一个元素小于或等于最后一个元素,且第一个元素就是最小值,此时直接返回第一个元素的值即可。所以middle的初始值为start. (2) 首末元素与中间元素相等时:由于首末元素与中间元素相等,无法判断中间元素属于递增子数组还是递减子数组,也就无法移动指针来改变查找范围,这种情况只能改用顺序查找。 @@ -37,55 +36,46 @@ tags: 二分查找 ## 代码 -### [c++代码](./src/cpp/旋转数组的最小数字.cpp) +### [c++代码](./src/cpp/011-旋转数组的最小数字.cpp) + +下面的代码书写方式保证了除了上面提到的特例, 也可以处理[0], [5 5 5 4 3 5]这样的输入 ```c++ -class Solution -{ - public: - int minNumberInRotateArray(vector rotateArray) - { - if (rotateArray.size() == 0) +class Solution { +public: + int minNumberInRotateArray(vector rotateArray) { + if(rotateArray.empty()) return 0; - - int index1 = 0, index2 = rotateArray.size() - 1; - int indexMid = index1; - - while (rotateArray[index1] >= rotateArray[index2]) - { - if (index2 - index1 == 1) - { - indexMid = index2; + int start=0,end=rotateArray.size()-1; + int middle=start; + while(rotateArray[start]>=rotateArray[end]){ + if(end-start==1){ + middle=end; break; } - indexMid = (index1 + index2) / 2; - - if (rotateArray[index1] == rotateArray[index2] && rotateArray[index1] == rotateArray[indexMid]) - return minInOrder(rotateArray, index1, index2); - - if (rotateArray[indexMid] >= rotateArray[index1]) - index1 = indexMid; - else if (rotateArray[indexMid] <= rotateArray[index2]) - index2 = indexMid; + middle=(start+end)>>1; + if(rotateArray[start]==rotateArray[middle]&&rotateArray[start]==rotateArray[end]){ + return MinInorder(rotateArray); + } + if(rotateArray[middle]>=rotateArray[start]) + start=middle; + else if(rotateArray[middle]<=rotateArray[end]) + end=middle; } - - return rotateArray[indexMid]; + return rotateArray[middle]; } - - int minInOrder(const vector rotateArray, int index1, int index2) - { - int minNum = rotateArray[index1]; - for (int i = index1; i <= index2; i++) - { - if (rotateArray[i] <= minNum) - minNum = rotateArray[i]; + int MinInorder(vector rotateArray){ + int result=rotateArray[0]; + for(int i=1;irotateArray[i]) + return rotateArray[i]; } - return minNum; + return result; } }; ``` -### [python代码](./src/python/旋转数组的最小数字.py) +### [python代码](./src/python/011-旋转数组的最小数字.py) ```python # -*- coding:utf-8 -*- @@ -120,4 +110,8 @@ class Solution: return minNum ``` -[1]:./img/查找旋转数组最小数字过程.png \ No newline at end of file +[1]:./img/查找旋转数组最小数字过程.png + +### 扩展 + +书里p80有快速排序的代码 \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/cpp/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.cpp" "b/\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/cpp/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.cpp" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/cpp/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.cpp" rename to "\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/cpp/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.cpp" diff --git "a/\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/python/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" "b/\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/python/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" similarity index 100% rename from "\345\211\221\346\214\207offer/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/python/\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" rename to "\345\211\221\346\214\207offer/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227/src/python/011-\346\227\213\350\275\254\346\225\260\347\273\204\347\232\204\346\234\200\345\260\217\346\225\260\345\255\227.py" diff --git "a/\345\211\221\346\214\207offer/012-\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204/readme.md" "b/\345\211\221\346\214\207offer/012-\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204/readme.md" new file mode 100644 index 0000000..697d33a --- /dev/null +++ "b/\345\211\221\346\214\207offer/012-\347\237\251\351\230\265\344\270\255\347\232\204\350\267\257\345\276\204/readme.md" @@ -0,0 +1,95 @@ +# 012-矩阵中的路径 + +tags: 回溯法 深度优先遍历DFS + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/questionTerminal/c61c6999eecb4b8f88a98f66b273a3cc) + +请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。 + +``` +a b c e +s f c s +a d e e +``` + +## 解题思路 + +> [参考](https://www.cnblogs.com/tianzeng/p/10134445.html) + +这是一个能够用回朔法解决的典型题。首先,在矩阵中任选一个格子作为路径的起点。假设矩阵中某个格子的字符为ch,那么这个格子不可能处在路径上的第i个位置。假设路径上的第i个字符不是ch。那么这个格子不可能处在路径上的第i个位置。假设路径上的第i个字符正好是ch。那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子之外,其它格子都有4个相邻的格子。反复这个过程知道路径上的全部字符都在矩阵中找到相应的位置。 + + +因为回朔法的递归特性,路径能够被看成一个栈。当在矩阵中定位了路径中前n个字符的位置之后。在与第n个字符相应的格子的周围都没有找到第n+1个字符。这个时候仅仅要在路径上回到第n-1个字符。又一次定位第n个字符。 + +因为路径不能反复进入矩阵的格子。还须要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 +当矩阵中坐标为(row,col)的格子和路径字符串中下标为pathLength的字符一样时。从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下标为pathLength+1的字符。 + +假设4个相邻的格子都没有匹配字符串中下标为pathLength+1的字符,表明当前路径字符串中下标为pathLength的字符在矩阵中的定位不对,我们须要回到前一个字符(pathLength-1),然后又一次定位。 + + +一直反复这个过程,直到路径字符串上全部字符都在矩阵中找到合适的位置 + +## 代码 + +### [c++代码](./src/cpp/012-矩阵中的路径.cpp) + +**注意:** hasPathCore()中的参数pathLength不是引用也可以, 但 visited一定要在迭代中保持状态同步. + +```c++ +class Solution { +public: + bool hasPath(char* matrix, int rows, int cols, char* str) + { + if(matrix==nullptr||rows<1||cols<1||str==nullptr) + return false; + int pathLength=0; + bool *visited =new bool[rows*cols]; + memset(visited,0,rows*cols);//把visited中元素初始化为false, 容易忘记 + for(int i=0;i=0&&col>=0&&row=0&&col>=0&&row=0&&row>=0&&col0){ + sum=sum+num%10; + num=num/10; + } + return sum; + } +}; +``` + +### [python代码](./src/python/013-机器人的运动范围.py) + +```python + +``` + diff --git "a/\345\211\221\346\214\207offer/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264/src/cpp/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.cpp" "b/\345\211\221\346\214\207offer/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264/src/cpp/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.cpp" new file mode 100644 index 0000000..8117185 --- /dev/null +++ "b/\345\211\221\346\214\207offer/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264/src/cpp/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.cpp" @@ -0,0 +1,43 @@ +class Solution { +public: + int movingCount(int threshold, int rows, int cols) + { + if(threshold<=0||rows<=0||cols<=0) + return 0; + bool* visited= new bool[rows*cols]; + memset(visited,0,rows*cols); + + int count=movingCountCore(threshold,rows,cols,0,0,visited); + delete[] visited; + + return count; + } + + int movingCountCore(int threshold, int rows, int cols, int row, int col , bool* visited){ + int count=0; + if(check(threshold,rows,cols,row,col,visited)){ + visited[row*cols+col]=true; + count=1+movingCountCore(threshold,rows,cols,row+1,col,visited)+ + movingCountCore(threshold,rows,cols,row-1,col,visited)+ + movingCountCore(threshold,rows,cols,row,col+1,visited)+ + movingCountCore(threshold,rows,cols,row,col-1,visited); + } + return count; + } + + bool check(int threshold, int rows, int cols, int row, int col , bool* visited){ + if(col>=0&&row>=0&&col0){ + sum=sum+num%10; + num=num/10; + } + return sum; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264/src/python/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.py" "b/\345\211\221\346\214\207offer/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264/src/python/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264/src/python/013-\346\234\272\345\231\250\344\272\272\347\232\204\350\277\220\345\212\250\350\214\203\345\233\264.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/readme.md" "b/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/readme.md" new file mode 100644 index 0000000..bedab0e --- /dev/null +++ "b/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/readme.md" @@ -0,0 +1,152 @@ +# 014-剪绳子 + +tags: 动态规划 贪婪算法 + +--- + +## 题目原文 + +[牛客网暂未收录]() + +题目:给你一根长度为n绳子,请把绳子剪成m段(m、n都是整数,n>1并且m≥1)。每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]*k[1]*…*k[m]可能的最大乘积是多少?例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到最大的乘积18。 + +## 解题思路 + +#### 动态规划 + +> [参考](https://blog.csdn.net/upupday19/article/details/79315885) + +需要O(n^2)时间和O(n)空间 + +设f(n)代表长度为n的绳子剪成若干段的最大乘积,如果第一刀下去,第一段长度是i,那么剩下的就需要剪n-i,那么f(n)=max{f(i)f(n-i)}。而f(n)的最优解对应着f(i)和f(n-i)的最优解,假如f(i)不是最优解,那么其最优解和f(n-i)乘积肯定大于f(n)的最优解,和f(n)达到最优解矛盾,所以f(n)的最优解对应着f(i)和f(n-i)的最优解。首先,剪绳子是最优解问题,其次,大问题包含小问题,并且大问题的最优解包含着小问题的最优解,所以可以使用动态规划求解问题,并且从小到大求解,把小问题的最优解记录在数组中,求大问题最优解时就可以直接获取,避免重复计算 + +n<2时,由于每次至少减一次,所以返回0。n=2时,只能剪成两个1,那么返回1。n=3时,可以剪成3个1,或者1和2,那么最大乘积是2。当n>3时,就可以使用公式进行求解。 + +f(4)=max{f(1)f(3), f(2)f(2)} +f(5)=max{f(1)f(4), f(2)f(3)} +... +f(n)=max{f(1)f(n-1), f(2)f(n-2), f(3)f(n-3), ..., f(i)(fn-i), ...} + +因为需要保证f(i)f(n-i)不重复,就需要保证i<=n/2,这是一个限制条件,求1~n/2范围内的乘积,得到最大值 + + +#### 贪婪算法 + +只需要O(1)时间和空间 + +n<2时,返回0;n=2时,返回1;n=3时,返回2 + +根据数学计算,当n>=5时,2(n-2)>n,3(n-3)>n,这就是说,将绳子剪成2和(n-2)或者剪成3和(n-3)时,乘积大于不剪的乘积,因此需要把绳子剪成2或者3。并且3(n-3)>=2(n-2),也就是说,当n>=5时,应该剪尽量多的3,可以使最后的乘积最大。对于长度是n的绳子,我们可以剪出n/3个3,剩余长度是1或者2,如果余数是1,就可以把1和最后一个3合并成4,那么4剪出两个2得到的乘积是4,比1*3大,因此这种情况下,需要将3的个数减少1,变成两个2;如果余数是2,那么无需做修改 + +可以得到最大的乘积是:3^timesOf3 * 2^timesOf2 + +相比动态规划,计算更简便,但是需要一定的数学技巧。 + +**至于为什么不可以用4(n-4)>n, 5(n-5)>n, 6(n-6)>n**. 我的想法是: 上面推导得到 + +- 尽量减3的乘积大于尽量减2的乘积 +- 当n>=5时, 绳子剪成2和(n-2)或者剪成3和(n-3)时,乘积大于不剪的乘积 + +那么如果绳子被划为abcd四段, 只要abcd中有长度大于5的, 那么就可以继续按3或按2拆分, 得到比之前更大的结果. + +那么按4拆分可以么, 可以发现按4拆分, 等效于按2拆分, 没有3^timesOf3 * 2^timesOf2的乘积大 + +那么按5拆分呢, 可以发现等效于按2拆分和按3拆分的数量一半一半, 但还没有3^timesOf3 * 2^timesOf2的乘积大 + +那么按6拆分呢, 可以发现把6拆分为3*3乘积比6大, 所以先按3后按2拆分的策略最好. + +### 注意 + +动态规划的c++代码中, products保存的是子问题的最优解, 所以products[3] = 3, 而不是2 + +贪婪算法的c++代码中, pow的返回值是double类型, 需要强制转换为int类型 + +## 代码 + +### [c++代码](./src/cpp/014-剪绳子.cpp) + +```c++ +// ====================动态规划==================== +int maxProductAfterCutting_solution1(int length) +{ + if (length < 2) + return 0; + if (length == 2) + return 1; + if (length == 3) + return 2; + + int* products = new int[length + 1]; + products[0] = 0; + products[1] = 1; + products[2] = 2; + products[3] = 3; + + int max = 0; + for (int i = 4; i <= length; ++i) + { + max = 0; + for (int j = 1; j <= i / 2; ++j) + { + int product = products[j] * products[i - j]; + if (max < product) + max = product; + + products[i] = max; + } + } + + max = products[length]; + delete[] products; + + return max; +} + +// ====================贪婪算法==================== +int maxProductAfterCutting_solution2(int length) +{ + if (length < 2) + return 0; + if (length == 2) + return 1; + if (length == 3) + return 2; + + // 尽可能多地减去长度为3的绳子段 + int timesOf3 = length / 3; + + // 当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段。 + // 此时更好的方法是把绳子剪成长度为2的两段,因为2*2 > 3*1。 + if (length - timesOf3 * 3 == 1) + timesOf3 -= 1; + + int timesOf2 = (length - timesOf3 * 3) / 2; + + return (int)(pow(3, timesOf3)) * (int)(pow(2, timesOf2)); +} +``` + +### [python代码](./src/python/014-剪绳子.py) + +```python + +``` + +### 拓展 切杆问题 + +#### 问题描述 + +切割杆,现有长度为n的杆,价值数组是prices[],数组长度是n,已知长度i对应的价值是prices[i-1],比如长度1对应的价值数是prices[0]。将其切割,求碎片的最大价值。 + +#### 思路 + + 假设第一刀切下来是i,那么剩下的是n-i,假设f(n)代表切割n所能获得的最大价值,那么f(n)=max{f(i)+f(n-i)},因此大问题可以分解成小问题,并且同剪绳子问题,大问题的最优解包括小问题的最优解,那么可以求出小问题的最优解,存到数组中,在求大问题最优解时就可以直接从数组中获取,最终获得最优解。 + f(0)=0 + f(1)=prices[0] + f(2)=max{prices[1], f(1)+f(1)} + f(3)=max{prices[2], f(1)+f(2)} + f(4)=max{prices[3], f(1)+f(3), f(2)+f(2)} + ... + f(n)=max{prices[n-1], f(1)+f(n-1), f(2)+f(n-2), ..., f(i)+f(n-i), ...} + +对于f(n),为了保证f(i)+f(n-i)不重复,需要保证i<=n/2,这也是循环次数限制条件,在1~n/2范围内求解。 \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/src/cpp/014-\345\211\252\347\273\263\345\255\220.cpp" "b/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/src/cpp/014-\345\211\252\347\273\263\345\255\220.cpp" new file mode 100644 index 0000000..ffcaebb --- /dev/null +++ "b/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/src/cpp/014-\345\211\252\347\273\263\345\255\220.cpp" @@ -0,0 +1,190 @@ +/******************************************************************* +Copyright(c) 2016, Harry He +All rights reserved. +Distributed under the BSD license. +(See accompanying file LICENSE.txt at +https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt) +*******************************************************************/ + +//================================================================== +// 《剑指Offer——名企面试官精讲典型编程题》代码 +// 作者:何海涛 +//================================================================== + +// 面试题14:剪绳子 +// 题目:给你一根长度为n绳子,请把绳子剪成m段(m、n都是整数,n>1并且m≥1)。 +// 每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]*k[1]*…*k[m]可能的最大乘 +// 积是多少?例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此 +// 时得到最大的乘积18。 + +#include +#include + +// ====================动态规划==================== +int maxProductAfterCutting_solution1(int length) +{ + if (length < 2) + return 0; + if (length == 2) + return 1; + if (length == 3) + return 2; + + int* products = new int[length + 1]; + products[0] = 0; + products[1] = 1; + products[2] = 2; + products[3] = 3; + + int max = 0; + for (int i = 4; i <= length; ++i) + { + max = 0; + for (int j = 1; j <= i / 2; ++j) + { + int product = products[j] * products[i - j]; + if (max < product) + max = product; + + products[i] = max; + } + } + + max = products[length]; + delete[] products; + + return max; +} + +// ====================贪婪算法==================== +int maxProductAfterCutting_solution2(int length) +{ + if (length < 2) + return 0; + if (length == 2) + return 1; + if (length == 3) + return 2; + + // 尽可能多地减去长度为3的绳子段 + int timesOf3 = length / 3; + + // 当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段。 + // 此时更好的方法是把绳子剪成长度为2的两段,因为2*2 > 3*1。 + if (length - timesOf3 * 3 == 1) + timesOf3 -= 1; + + int timesOf2 = (length - timesOf3 * 3) / 2; + + return (int)(pow(3, timesOf3)) * (int)(pow(2, timesOf2)); +} + +// ====================测试代码==================== +void test(const char* testName, int length, int expected) +{ + int result1 = maxProductAfterCutting_solution1(length); + if (result1 == expected) + std::cout << "Solution1 for " << testName << " passed." << std::endl; + else + std::cout << "Solution1 for " << testName << " FAILED." << std::endl; + + int result2 = maxProductAfterCutting_solution2(length); + if (result2 == expected) + std::cout << "Solution2 for " << testName << " passed." << std::endl; + else + std::cout << "Solution2 for " << testName << " FAILED." << std::endl; +} + +void test1() +{ + int length = 1; + int expected = 0; + test("test1", length, expected); +} + +void test2() +{ + int length = 2; + int expected = 1; + test("test2", length, expected); +} + +void test3() +{ + int length = 3; + int expected = 2; + test("test3", length, expected); +} + +void test4() +{ + int length = 4; + int expected = 4; + test("test4", length, expected); +} + +void test5() +{ + int length = 5; + int expected = 6; + test("test5", length, expected); +} + +void test6() +{ + int length = 6; + int expected = 9; + test("test6", length, expected); +} + +void test7() +{ + int length = 7; + int expected = 12; + test("test7", length, expected); +} + +void test8() +{ + int length = 8; + int expected = 18; + test("test8", length, expected); +} + +void test9() +{ + int length = 9; + int expected = 27; + test("test9", length, expected); +} + +void test10() +{ + int length = 10; + int expected = 36; + test("test10", length, expected); +} + +void test11() +{ + int length = 50; + int expected = 86093442; + test("test11", length, expected); +} + +int main(int agrc, char* argv[]) +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + system("pause"); + return 0; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/src/python/014-\345\211\252\347\273\263\345\255\220.py" "b/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/src/python/014-\345\211\252\347\273\263\345\255\220.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/014-\345\211\252\347\273\263\345\255\220/src/python/014-\345\211\252\347\273\263\345\255\220.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/readme.md" new file mode 100644 index 0000000..6f1a739 --- /dev/null +++ "b/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/readme.md" @@ -0,0 +1,149 @@ +# 015-二进制中1的个数 + +tags: 位运算 + +--- + +## 题目描述 + +[牛客网链接](https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040ea7fbb10b8?tpId=13&tqId=11164&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) + +输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 + +**样例输入** + +> 3 4 5 -1 + +**样例输出** + +> 1 2 3 2 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/010-%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%B8%AD1%E7%9A%84%E4%B8%AA%E6%95%B0](https://github.com/gatieme/CodingInterviews/tree/master/010-二进制中1的个数)) + +### 思路1 通过右移测试每一位 + +我们很容易想到的算法就是 + +通过移位的方法,挨个判断其每一位 + +```c++ +class Solution +{ +public: + int NumberOf1(int n) + { + int count = 0; + + while(n) + { + if(n & 1 == 1) + { + count++; + } + n >>= 1; + } + return count; + } +}; +``` + +但是这个算法有致命的缺陷,我们假设通过移位的方式可以获取到其每一位,但是并不总是对的. 这是由于右移的特点决定的 + +### 左移与右移 + +左移运算符m<>n表示把m右移n位. 在右移n位的时候, 最右边的n位被丢弃, 但是在处理最左边的情形要复杂一些. 如果数字为无符号数, 则用0补上最左边的n位. 如果数字是有符号数要分情况, 如果为正数, 则用0补上, 如果是负数, 就用1补上. 下面是两个8位有符号数右移的例子 + +``` +00001010>>2=00000010 +10001010>>3=11110001 +``` + +所以上面用右移的解法存在的问题是, 如果输入是负数, 右移后最高位会被设为1, 如果一直做右移运算, 数字永远不会为0, 陷入死循环. + +### 思路2 用左移 + +为了负数时候避免死循环,我们可以**不右移数字n,转而去移动测试位** + +```c++ +class Solution +{ +public: + int NumberOf1(int n) + { + int count = 0; + unsigned int flag = 1; + + while(flag != 0) + { + if((n & flag) != 0) + { + count++; + } + flag <<= 1; + } + + return count; + } + +}; +``` + +这种方法循环的次数正好是是整数二进制数的位数,比如int就是32位循环32次 + +那么有没有一种方法,整数中有几个1就循环几次呢? + + + +### 思路3 整数中有几个1就循环几次--lowbit优化 + +我们分析n以n-1两个数的差别, + +- 如果n!=0,那么其二进制位中至少有一个1 +- 如果n的最低位是1(奇数),那么n-1正好把这个最低位的1变成0,其他位不变 +- 如果n的最低位是0(偶数),那么假设其右起第一个1位于m位,即m位后面全是0,那么n-1的第m位由1变成0,而第m位后面的所有0均变成1,m位之前的所有位保持不变。 + +因此通过分析发现: + +**把一个整数n减去1,再和原来的整数做与运算,会把该整数最右边一个1变成0,那么该整数有多少个1,就会进行多少次与运算** + +即循环的次数,即二进制中1的个数 + +> 如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。 + +## 代码 +### [c++代码](./src/cpp/015-二进制中1的个数.cpp) + +```c++ +class Solution { +public: + int NumberOf1(int n) { + int count=0; + + while(n){ + count++; + n=(n-1)&n; + } + + return count; + } +}; +``` + +但是这个算法有致命的缺陷,我们假设通过移位的方式可以获取到其每一位,但是并不总是对的 + + + +### [python代码](./src/python/015-二进制中1的个数.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/cpp/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.cpp" "b/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/cpp/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.cpp" new file mode 100644 index 0000000..1a9d77a --- /dev/null +++ "b/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/cpp/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.cpp" @@ -0,0 +1,13 @@ +class Solution { +public: + int NumberOf1(int n) { + int count=0; + + while(n){ + count++; + n=(n-1)&n; + } + + return count; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/python/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" "b/\345\211\221\346\214\207offer/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/src/python/015-\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260.py" new file mode 100644 index 0000000..e69de29 diff --git "a/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/img/readme.assets/3270776_1504711188579_E695B0E580BCE79A84E695B4E695B0E6ACA1E696B9.png" "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/img/readme.assets/3270776_1504711188579_E695B0E580BCE79A84E695B4E695B0E6ACA1E696B9.png" new file mode 100644 index 0000000..c0dc65c Binary files /dev/null and "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/img/readme.assets/3270776_1504711188579_E695B0E580BCE79A84E695B4E695B0E6ACA1E696B9.png" differ diff --git "a/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/img/readme.assets/3270776_1504748011304_B16239181123036ECE974C89CC410F1F.png" "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/img/readme.assets/3270776_1504748011304_B16239181123036ECE974C89CC410F1F.png" new file mode 100644 index 0000000..d6cb466 Binary files /dev/null and "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/img/readme.assets/3270776_1504748011304_B16239181123036ECE974C89CC410F1F.png" differ diff --git "a/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/readme.md" "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/readme.md" new file mode 100644 index 0000000..af1bfe7 --- /dev/null +++ "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/readme.md" @@ -0,0 +1,340 @@ +# 016-数值的整数次方 + +tags: 快速求幂算法 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/1a834e5e3e1a4b7ba251417554e07c00?tpId=13&tqId=11165&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) + +给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/011-%E6%95%B0%E5%80%BC%E7%9A%84%E6%95%B4%E6%95%B0%E6%AC%A1%E6%96%B9](https://github.com/gatieme/CodingInterviews/tree/master/011-数值的整数次方)) + +[参考](https://www.nowcoder.com/questionTerminal/1a834e5e3e1a4b7ba251417554e07c00) + +这道题除了快速求幂算法稍微有些难度, 其余的比较简单. + +这道题考察的是思维的全面性, 一个是要考虑各种情况, 另一个是快速求幂, 在一个是c++的易错点和加速技巧. + +### 自以为很简单的解法 + +```c++ +class Solution +{ +public: + double Power(double base, int exponent) + { + double res = 1; + for(int i = 0; i < exponent; i++) + { + res *= base; + } + + return res; + } +}; +``` + +貌似我们已经完美的解决了问题,但是真的这样么? 我们输入一个指数为负数的情况 + +``` + Solution solu; + cout < 0.0) + { + res = PowerNormal(base, exponent); + } + else + { + res = PowerNormal(base, -exponent); + res = 1 / res; + } + + return res; + } + +private : + double PowerNormal(double base, int exponent) + { + + double res = 1; + for(int i = 0; i < exponent; i++) + { + res *= base; + } + + return res; + + } + double Equal(double left, double right) + { + if(fabs(left - right) < 0.0000001) + { + return true; + } + else + { + return false; + } + } +}; +``` + +### 全面且高效的算法 快速求幂算法 + +幂运算有如下性质 + +![img](img/readme.assets/3270776_1504711188579_E695B0E580BCE79A84E695B4E695B0E6ACA1E696B9.png) + +![img](img/readme.assets/3270776_1504748011304_B16239181123036ECE974C89CC410F1F.png) + +快速幂乘法有两种实现思路, 一种是循环, 一种是递归 + +#### 循环 + +我用的是循环版本 + +[参考](https://blog.csdn.net/hkdgjqr/article/details/5381028) + +快速求正整数次幂,当然不能直接死乘。举个例子: + +3 ^ 999 = 3 * 3 * 3 * … * 3 + +直接乘要做998次乘法。但事实上可以这样做,先求出2^k次幂: + +3 ^ 2 = 3 * 3 +3 ^ 4 = (3 ^ 2) * (3 ^ 2) +3 ^ 8 = (3 ^ 4) * (3 ^ 4) +3 ^ 16 = (3 ^ 8) * (3 ^ 8) +3 ^ 32 = (3 ^ 16) * (3 ^ 16) +3 ^ 64 = (3 ^ 32) * (3 ^ 32) +3 ^ 128 = (3 ^ 64) * (3 ^ 64) +3 ^ 256 = (3 ^ 128) * (3 ^ 128) +3 ^ 512 = (3 ^ 256) * (3 ^ 256) + +再相乘: + +3 ^ 999 += 3 ^ (512 + 256 + 128 + 64 + 32 + 4 + 2 + 1) += (3 ^ 512) * (3 ^ 256) * (3 ^ 128) * (3 ^ 64) * (3 ^ 32) * (3 ^ 4) * (3 ^ 2) * 3 + +这样只要做16次乘法。即使加上一些辅助的存储和运算,也比直接乘高效得多(尤其如果这里底数是成百上千位的大数字的话)。 + +我们发现,把999转为2进制数:1111100111,其各位就是要乘的数。这提示我们利用求二进制位的算法(其中mod是模运算): + +REVERSE_BINARY(n) +1 while (n > 0) +2 do output (n mod 2) +3 n ← n / 2 + +这个算法给出正整数n的反向二制进位,如6就给出011(6的二进制表示为110)。事实上这个算法对任意的p进制数是通用的,只要把其中的2换成p就可以了。 + +如何把它改编为求幂运算?我们发现这个算法是从低位向高位做的,而恰好我们求幂也想从低次幂向高次幂计算(参看前面的例子)。而且我们知道前面求出的每个2^k次幂只参与一次乘法运算,这就提示我们并不把所有的中间结果保存下来,而是在计算出它们后就立即运算。于是,我们要做的就是把输出语句改为要做的乘法运算,并在n减少的同时不断地累积求2^k次幂。 + +还是看算法吧: + +POWER_INTEGER(x, n) +1 pow ← 1 +2 while (n > 0) +3 do if (n mod 2 = 1) +4 then pow ← pow * x +5 x ← x * x +6 n ← n / 2 +7 return pow + +不难看出这个算法与前面算法的关系。在第1步给出结果的初值1,在while循环内进行运算。3、4中的if语句就来自REVERSE_BINARY的输出语句,不过改成了如果是1则向pow中乘。5句则是不断地计算x的2^k次幂,如对前面的例子就是计算2^2、2^4、2^8、…、2^512。 + +应该指出,POWER_INTEGER比前面分析的要再多做两次乘法,一次是向pow中第一次乘x,如2^1也要进行这个乘法;另一次则是在算法的最后,n除以2后该跳出循环,而前面一次x的自乘就浪费掉了(也可以考虑改变循环模式优化掉它)。另外,每趟while循环都要进行一次除法和一次模运算,这多数情况下除法和模运算都比乘法慢许多,不过好在我们往往可以用位运算来代替它 + +注1:快速求幂算法POWER_INTEGER常被写成递归的形式,算法实质完全相同,但却是无必要的。 + +注2:这个算法并不是做乘法数最少的,但多数情况下是足够快并且足够简单的。如果单纯追求做乘法数最少,则未必应该用2^k次幂进行计算。如果还允许做除法,则问题会进一步复杂化。 + +#### 递归 + +[参考](https://www.jianshu.com/p/148006beb244) + +递归则是用如下公式 + +``` +base^n = base^(n/2) * base^(n/2); +base^n = base * base^((n-1)/2) * base^((n-1)/2); +``` + +这样分解下去,就可以把时间复杂度降为`O(logN)`。 + +```c++ +double tiny_pow(double base, int n) +{ + // 0的0次方极限趋近于1. 0^-1,0^-2会引起CPU异常,所以不作处理 + if (equal(base, 0.0) && n == 0) + return 0.0; + + unsigned int absN = ( n > 0 ? (unsigned int)n : abs(n) ); + + double result = powWithUnsignedN(base, absN); + if (n < 0) + result = 1.0 / result; + + return result; +} + +double powWithUnsignedN(double base, unsigned int n) +{ + if (n == 0) return 1; + + if (n == 1) return base; // 也是递归开始回溯的地方 + + double result = powWithUnsignedN(base, n >> 1); + result *= result ; + + if (n & 1) // n为奇数 + result *= base; + + return result ; +} + +bool equal(double num1, double num2) +{ + // |num1 - num2| < 0.0000001 + if (-0.0000001 < (num1 - num2) && (num1 - num2) < 0.0000001) + return true; + else + return false; +} +``` + +### 总结 + +#### **思维全面性:** + +1. 全面考察指数的正负、底数是否为零等情况。 + +当底数为0且指数<0时, 会出现对0求倒数的情况,需进行错误处理 + +2. 0的0次幂在数学上是无意义的, 因此返回0还是1都可以接受, 但是要和面试官说清楚 + +#### **编程易错点** + +1. C++浮点数(float、double)类型数据比较、相等判断 + +浮**点数**在内存中的存储机制和整型数不同,其有舍入误差,在计算机中用近似表示任意某个实数。**float小数点前后加起来有效数字只有6位**。**double小数前后加起来的有效数字只有16位** + +**用"=="来比较两个double应该相等的类型,返回真值完全是不确定的**。计算机对浮**点数**的进行计算的原理是只保证必要精度内正确即可。 + +我们在**判断**浮**点数相等**时,推荐用范围来确定,若x在某一范围内,我们就认为**相等**,至于范围怎么定义,要看实际情况而已了,float,和double 各有不同 + 所以const float EPSINON = 0.00001; + if((x >= - EPSINON) && (x <= EPSINON) 这样**判断**是可取的至于为什么取0.00001,可以自己按实际情况定义。 + +​ 也可以 abs(x) <= EPSINON + +比如要**判断**浮**点数**floatA和B是否**相等**,我们先令float x = A –B ; + +并设constfloat EPSINON = 0.00001; 则 + +if ((x >= - EPSINON)&& (x <= EPSINON);//或者if(abs(x) <= EPSINON) + +cout<<”A 与B**相等**<>= 1 等价于 n /= 2 +``` + + + +## 代码 + +### [c++代码](./src/cpp/016-数值的整数次方.cpp) + +```c++ +class Solution { +public: + double Power(double base, int exponent) { + double res=1,cur=base; + unsigned int n; + if(exponent>0){ + n=(unsigned int)(exponent); + }else if(exponent<0){ + if(fabs(base-0)<0.00000001) + throw new logic_error("分母不能为0"); + n=(unsigned int)(-exponent); + }else{// n==0 + return 1;// 0的0次方 + } + + while(n){ + if((n&0x01)==1) + res*=cur; + cur*=cur;// 翻倍 + n>>=1;// 右移一位 + } + + return exponent>=0?res:(1/res); + } +}; +``` + +### [python代码](./src/python/016-数值的整数次方.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/src/cpp/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.cpp" "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/src/cpp/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.cpp" new file mode 100644 index 0000000..b74c69a --- /dev/null +++ "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/src/cpp/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.cpp" @@ -0,0 +1,25 @@ +class Solution { +public: + double Power(double base, int exponent) { + double res=1,cur=base; + unsigned int n; + if(exponent>0){ + n=(unsigned int)(exponent); + }else if(exponent<0){ + if(fabs(base-0)<0.00000001) + throw new logic_error("分母不能为0"); + n=(unsigned int)(-exponent); + }else{// n==0 + return 1;// 0的0次方 + } + + while(n){ + if((n&0x01)==1) + res*=cur; + cur*=cur;// 翻倍 + n>>=1;// 右移一位 + } + + return exponent>=0?res:(1/res); + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/src/python/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.py" "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/src/python/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271/src/python/016-\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/readme.md" new file mode 100644 index 0000000..47e6fe2 --- /dev/null +++ "b/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/readme.md" @@ -0,0 +1,402 @@ +# 017-打印1到最大的n位数 + +tags: 大数 全排列 + +--- + +## 题目原文 + +[牛客网链接 暂无]() + +**题目描述** + +> 给定一个数字N,打印从1到最大的N位数。 + +**输入** + +> 每个输入文件仅包含一组测试样例。 +> +> 对于每个测试案例,输入一个数字N(1<=N<=5)。 **输出** 对应每个测试案例,依次打印从1到最大的N位数。 + +**样例输入** + +> 1 + +**样例输出** + +> 1 2 3 4 5 6 7 8 9 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/012-%E6%89%93%E5%8D%B01%E5%88%B0%E6%9C%80%E5%A4%A7%E7%9A%84N%E4%BD%8D%E6%95%B0](https://github.com/gatieme/CodingInterviews/tree/master/012-打印1到最大的N位数)) + +### 最简单的解法--跳进面试官的陷阱 + +好像没有什么问题,但是仔细分析你就会发现,N的范围并不确定,我们没法保证这些数是不是超出了INT_MAX的表示范围。 + +```c++ +class Solutin +{ +public : + void Print(int n) + { + int max = pow(10, n); + for(int i = 1; i < max; i++) + { + cout <= 0; i--) + { + int nSum = number[i] - '0' + nTakeOver; + if (i == nLength - 1) + nSum++; + + if (nSum >= 10) + { + if (i == 0) + isOverflow = true; + else + { + nSum -= 10; + nTakeOver = 1; + number[i] = '0' + nSum; + } + } + else + { + number[i] = '0' + nSum; + break; + } + } + + return isOverflow; +} + +// ====================公共函数==================== +// 字符串number表示一个数字,数字有若干个0开头 +// 打印出这个数字,并忽略开头的0 +void PrintNumber(char* number) +{ + bool isBeginning0 = true; + int nLength = strlen(number); + + for (int i = 0; i < nLength; ++i) + { + if (isBeginning0 && number[i] != '0') + isBeginning0 = false; + + if (!isBeginning0) + { + printf("%c", number[i]); + } + } + + printf("\t"); +} +``` + + + +### 递归--转换为数字排列的解法 + +上面的算法已经很不错了,但是代码复杂,要在短时间内完成这样思路清晰而缜密的代码有点困难,因此我们需要更加简洁的方法 + +> 如果我们在数字前面补上0的话,那么我们发现,n位所有的十进制数起始就是n个从0到9的全排列。 +> +> 也就是说,我们把数字的每一位都从0到9排列一遍,就得到了所有的十进制数。 + +只要我们在打印的时候,数字排在前面的0不用打印出来而已。 + +- 全排列用递归很容易表示,数字的每一位都可能是0~9中的一个数,然后设置下一位。 +- 递归结束的条件是我们已经设置了数字的最后一位 + +```c++ +// ====================方法二==================== +void Print1ToMaxOfNDigits_2(int n) +{ + if (n <= 0) + return; + + char* number = new char[n + 1]; + number[n] = '\0'; + + for (int i = 0; i < 10; ++i) + { + number[0] = i + '0'; + Print1ToMaxOfNDigitsRecursively(number, n, 0); + } + + delete[] number; +} + +void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index) +{ + if (index == length - 1) + { + PrintNumber(number); + return; + } + + for (int i = 0; i < 10; ++i) + { + number[index + 1] = i + '0'; + Print1ToMaxOfNDigitsRecursively(number, length, index + 1); + } +} + +// ====================公共函数==================== +// 字符串number表示一个数字,数字有若干个0开头 +// 打印出这个数字,并忽略开头的0 +void PrintNumber(char* number) +{ + bool isBeginning0 = true; + int nLength = strlen(number); + + for (int i = 0; i < nLength; ++i) + { + if (isBeginning0 && number[i] != '0') + isBeginning0 = false; + + if (!isBeginning0) + { + printf("%c", number[i]); + } + } + + printf("\t"); +} +``` + +## 相关题目 + +前面的代码中,我们都是用一个char型字符表示十进制数字的一位。 8个bit的char型字符最多能表示256个字符,而十进制数字只有0-9的10个数字。 因此用char型字符串来表示十进制的数字并没有充分利用内存,有一些浪费。 有没有更高效的方式来表示大数。 + +可以使用**bitmap算法**,这个很有意思。特别是在数据量大的时候,非常高效 +所谓bitmap就是用一个bit位来标记某个元素对应的value,而key即是这个元素。由于采用bit为单位来存储数据,因此在可以大大的节省存储空间。 + +十进制表示方法,不止一种 +ASCII +BCD +压缩BCD +这些都是十进制编码,其中压缩BCD可以多存储一倍的数据 +其他, +16Bits 可以表示万进制 +32Bits 可以表示亿进制,10 亿进制 +这些和十进制优势关系密切的表示方法,转换简单 +另外一种 多 字节(字,双字,四字)串 表示方法, +是 二进制表示法, +和十进制转换不太方便,不过+,-,*,/ 等数学运算,实现方便. + +## 代码 + +### [c++代码](./src/cpp/017-打印1到最大的n位数.cpp) + +```c++ +/******************************************************************* +Copyright(c) 2016, Harry He +All rights reserved. +Distributed under the BSD license. +(See accompanying file LICENSE.txt at +https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt) +*******************************************************************/ + +//================================================================== +// 《剑指Offer——名企面试官精讲典型编程题》代码 +// 作者:何海涛 +//================================================================== + +// 面试题17:打印1到最大的n位数 +// 题目:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则 +// 打印出1、2、3一直到最大的3位数即999。 + +#include +#include + +void PrintNumber(char* number); +bool Increment(char* number); +void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index); + +// ====================方法一==================== +void Print1ToMaxOfNDigits_1(int n) +{ + if (n <= 0) + return; + + char *number = new char[n + 1]; + memset(number, '0', n); + number[n] = '\0'; + + while (!Increment(number)) + { + PrintNumber(number); + } + + delete[]number; +} + +// 字符串number表示一个数字,在 number上增加1 +// 如果做加法溢出,则返回true;否则为false +bool Increment(char* number) +{ + bool isOverflow = false; + int nTakeOver = 0; + int nLength = strlen(number); + + for (int i = nLength - 1; i >= 0; i--) + { + int nSum = number[i] - '0' + nTakeOver; + if (i == nLength - 1) + nSum++; + + if (nSum >= 10) + { + if (i == 0) + isOverflow = true; + else + { + nSum -= 10; + nTakeOver = 1; + number[i] = '0' + nSum; + } + } + else + { + number[i] = '0' + nSum; + break; + } + } + + return isOverflow; +} + +// ====================方法二==================== +void Print1ToMaxOfNDigits_2(int n) +{ + if (n <= 0) + return; + + char* number = new char[n + 1]; + number[n] = '\0'; + + for (int i = 0; i < 10; ++i) + { + number[0] = i + '0'; + Print1ToMaxOfNDigitsRecursively(number, n, 0); + } + + delete[] number; +} + +void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index) +{ + if (index == length - 1) + { + PrintNumber(number); + return; + } + + for (int i = 0; i < 10; ++i) + { + number[index + 1] = i + '0'; + Print1ToMaxOfNDigitsRecursively(number, length, index + 1); + } +} + +// ====================公共函数==================== +// 字符串number表示一个数字,数字有若干个0开头 +// 打印出这个数字,并忽略开头的0 +void PrintNumber(char* number) +{ + bool isBeginning0 = true; + int nLength = strlen(number); + + for (int i = 0; i < nLength; ++i) + { + if (isBeginning0 && number[i] != '0') + isBeginning0 = false; + + if (!isBeginning0) + { + printf("%c", number[i]); + } + } + + printf("\t"); +} + +// ====================测试代码==================== +void Test(int n) +{ + printf("Test for %d begins:\n", n); + + Print1ToMaxOfNDigits_1(n); + Print1ToMaxOfNDigits_2(n); + + printf("\nTest for %d ends.\n", n); +} + +int main(int argc, char* argv[]) +{ + Test(1); + Test(2); + Test(3); + Test(0); + Test(-1); + system("pause"); + return 0; +} + +``` + +### [python代码](./src/python/017-打印1到最大的n位数.py) + +```python + +``` + +## 举一反三 + diff --git "a/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/src/cpp/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.cpp" "b/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/src/cpp/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.cpp" new file mode 100644 index 0000000..63f6a29 --- /dev/null +++ "b/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/src/cpp/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.cpp" @@ -0,0 +1,153 @@ +/******************************************************************* +Copyright(c) 2016, Harry He +All rights reserved. +Distributed under the BSD license. +(See accompanying file LICENSE.txt at +https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt) +*******************************************************************/ + +//================================================================== +// 《剑指Offer——名企面试官精讲典型编程题》代码 +// 作者:何海涛 +//================================================================== + +// 面试题17:打印1到最大的n位数 +// 题目:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则 +// 打印出1、2、3一直到最大的3位数即999。 + +#include +#include + +void PrintNumber(char* number); +bool Increment(char* number); +void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index); + +// ====================方法一==================== +void Print1ToMaxOfNDigits_1(int n) +{ + if (n <= 0) + return; + + char *number = new char[n + 1]; + memset(number, '0', n); + number[n] = '\0'; + + while (!Increment(number)) + { + PrintNumber(number); + } + + delete[]number; +} + +// 字符串number表示一个数字,在 number上增加1 +// 如果做加法溢出,则返回true;否则为false +bool Increment(char* number) +{ + bool isOverflow = false; + int nTakeOver = 0; + int nLength = strlen(number); + + for (int i = nLength - 1; i >= 0; i--) + { + int nSum = number[i] - '0' + nTakeOver; + if (i == nLength - 1) + nSum++; + + if (nSum >= 10) + { + if (i == 0) + isOverflow = true; + else + { + nSum -= 10; + nTakeOver = 1; + number[i] = '0' + nSum; + } + } + else + { + number[i] = '0' + nSum; + break; + } + } + + return isOverflow; +} + +// ====================方法二==================== +void Print1ToMaxOfNDigits_2(int n) +{ + if (n <= 0) + return; + + char* number = new char[n + 1]; + number[n] = '\0'; + + for (int i = 0; i < 10; ++i) + { + number[0] = i + '0'; + Print1ToMaxOfNDigitsRecursively(number, n, 0); + } + + delete[] number; +} + +void Print1ToMaxOfNDigitsRecursively(char* number, int length, int index) +{ + if (index == length - 1) + { + PrintNumber(number); + return; + } + + for (int i = 0; i < 10; ++i) + { + number[index + 1] = i + '0'; + Print1ToMaxOfNDigitsRecursively(number, length, index + 1); + } +} + +// ====================公共函数==================== +// 字符串number表示一个数字,数字有若干个0开头 +// 打印出这个数字,并忽略开头的0 +void PrintNumber(char* number) +{ + bool isBeginning0 = true; + int nLength = strlen(number); + + for (int i = 0; i < nLength; ++i) + { + if (isBeginning0 && number[i] != '0') + isBeginning0 = false; + + if (!isBeginning0) + { + printf("%c", number[i]); + } + } + + printf("\t"); +} + +// ====================测试代码==================== +void Test(int n) +{ + printf("Test for %d begins:\n", n); + + Print1ToMaxOfNDigits_1(n); + Print1ToMaxOfNDigits_2(n); + + printf("\nTest for %d ends.\n", n); +} + +int main(int argc, char* argv[]) +{ + Test(1); + Test(2); + Test(3); + Test(0); + Test(-1); + system("pause"); + return 0; +} diff --git "a/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/src/python/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.py" "b/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/src/python/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260/src/python/017-\346\211\223\345\215\2601\345\210\260\346\234\200\345\244\247\347\232\204n\344\275\215\346\225\260.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/272317431874277.jpg" "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/272317431874277.jpg" new file mode 100644 index 0000000..8d21d28 Binary files /dev/null and "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/272317431874277.jpg" differ diff --git "a/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/272359583447249.jpg" "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/272359583447249.jpg" new file mode 100644 index 0000000..ae5c6a7 Binary files /dev/null and "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/272359583447249.jpg" differ diff --git "a/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/280011268903804.png" "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/280011268903804.png" new file mode 100644 index 0000000..dff3ffa Binary files /dev/null and "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/img/readme.assets/280011268903804.png" differ diff --git "a/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/readme.md" "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/readme.md" new file mode 100644 index 0000000..d2d4983 --- /dev/null +++ "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/readme.md" @@ -0,0 +1,115 @@ +# 018_01-在O(1)时间删除链表结点 + +tags: 链表 + +--- + +## 题目原文 + +[牛客网链接_暂无]() +题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。 + + + +## 解题思路 + +[参考](https://www.cnblogs.com/edisonchou/p/4765163.html) + +### 常规思路 + + 在单向链表中删除一个结点,最常规的做法无疑是从链表的头结点开始,顺序遍历查找要删除的结点,并在链表中删除该结点。这种思路由于需要顺序查找,时间复杂度自然就是**O(n)**。 + +![img](img/readme.assets/272317431874277.jpg) + +### 正确思路 + +是不是一定需要得到被删除的结点的前一个结点呢?答案是否定的。 + +  我们可以很方便地得到要删除的结点的一下结点。因此,我们**可以把下一个结点的内容复制到需要删除的结点上覆盖原有的内容,再把下一个结点删除,就相当于把当前需要删除的结点删除了**。 + +![img](img/readme.assets/272359583447249.jpg) + +  但是,还有两个特殊情况需要进行考虑: + +  (1)如果要删除的结点位于链表的尾部,那么它就没有下一个结点: + +  此时我们仍然从链表的头结点开始,顺序遍历得到该结点的前序结点,并完成删除操作,这仍然属于O(n)时间的操作。 + +  (2)如果链表中只有一个结点,而我们又要删除链表的头结点(也是尾结点): + +  此时我们在删除结点之后,还需要把链表的头结点设置为NULL。 + +  最后,通过综合最坏情况(尾节点需要顺序查找,1次)和最好情况(n-1次),因此平均时间复杂度为: + +![img](img/readme.assets/280011268903804.png) + +  需要注意的是:**受到O(1)时间的限制,我们不得不把确保结点在链表中的责任推给了函数DeleteNode的调用者**。 + +## 编程知识 + +[C++ 里 delete 指针两次会怎么样?](https://www.zhihu.com/question/38998078#answer-41205877) + +## 代码 + +### [c++代码](./src/cpp/018_01-在O(1)时间删除链表结点.cpp) + +大体思路 + +``` +待删指针不是尾指针: + 待删指针的值用待删指针的下一个指针的值覆盖 + 删掉待删指针的下一个指针 +待删指针是尾指针: + 待删指针同时是头指针: + 删掉头指针 + 待删指针不是头指针 + 找到待删指针的前一个指针 + 删掉待删指针,前一个指针的next赋值为空 +``` + + + +```c++ +void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) +{ + if(!pListHead || !pToBeDeleted) + return; + + // 要删除的结点不是尾结点 + if(pToBeDeleted->m_pNext != nullptr) + { + ListNode* pNext = pToBeDeleted->m_pNext; + pToBeDeleted->m_nValue = pNext->m_nValue; + pToBeDeleted->m_pNext = pNext->m_pNext; + + delete pNext; + pNext = nullptr; + } + // 链表只有一个结点,删除头结点(也是尾结点) + else if(*pListHead == pToBeDeleted) + { + delete pToBeDeleted; + pToBeDeleted = nullptr; + *pListHead = nullptr; + } + // 链表中有多个结点,删除尾结点 + else + { + ListNode* pNode = *pListHead; + while(pNode->m_pNext != pToBeDeleted) + { + pNode = pNode->m_pNext; + } + + pNode->m_pNext = nullptr; + delete pToBeDeleted; + pToBeDeleted = nullptr; + } +} +``` + +### [python代码](./src/python/018_01-在O(1)时间删除链表结点.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/cpp/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.cpp" "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/cpp/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.cpp" new file mode 100644 index 0000000..820c8fa --- /dev/null +++ "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/cpp/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.cpp" @@ -0,0 +1,153 @@ +/******************************************************************* +Copyright(c) 2016, Harry He +All rights reserved. +Distributed under the BSD license. +(See accompanying file LICENSE.txt at +https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt) +*******************************************************************/ + +//================================================================== +// 《剑指Offer——名企面试官精讲典型编程题》代码 +// 作者:何海涛 +//================================================================== + +// 面试题18(一):在O(1)时间删除链表结点 +// 题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该 +// 结点。 + +#include +#include "..\Utilities\List.h" + +void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted) +{ + if(!pListHead || !pToBeDeleted) + return; + + // 要删除的结点不是尾结点 + if(pToBeDeleted->m_pNext != nullptr) + { + ListNode* pNext = pToBeDeleted->m_pNext; + pToBeDeleted->m_nValue = pNext->m_nValue; + pToBeDeleted->m_pNext = pNext->m_pNext; + + delete pNext; + pNext = nullptr; + } + // 链表只有一个结点,删除头结点(也是尾结点) + else if(*pListHead == pToBeDeleted) + { + delete pToBeDeleted; + pToBeDeleted = nullptr; + *pListHead = nullptr; + } + // 链表中有多个结点,删除尾结点 + else + { + ListNode* pNode = *pListHead; + while(pNode->m_pNext != pToBeDeleted) + { + pNode = pNode->m_pNext; + } + + pNode->m_pNext = nullptr; + delete pToBeDeleted; + pToBeDeleted = nullptr; + } +} + +// ====================测试代码==================== +void Test(ListNode* pListHead, ListNode* pNode) +{ + printf("The original list is: \n"); + PrintList(pListHead); + + printf("The node to be deleted is: \n"); + PrintListNode(pNode); + + DeleteNode(&pListHead, pNode); + + printf("The result list is: \n"); + PrintList(pListHead); +} + +// 链表中有多个结点,删除中间的结点 +void Test1() +{ + ListNode* pNode1 = CreateListNode(1); + ListNode* pNode2 = CreateListNode(2); + ListNode* pNode3 = CreateListNode(3); + ListNode* pNode4 = CreateListNode(4); + ListNode* pNode5 = CreateListNode(5); + + ConnectListNodes(pNode1, pNode2); + ConnectListNodes(pNode2, pNode3); + ConnectListNodes(pNode3, pNode4); + ConnectListNodes(pNode4, pNode5); + + Test(pNode1, pNode3); + + DestroyList(pNode1); +} + +// 链表中有多个结点,删除尾结点 +void Test2() +{ + ListNode* pNode1 = CreateListNode(1); + ListNode* pNode2 = CreateListNode(2); + ListNode* pNode3 = CreateListNode(3); + ListNode* pNode4 = CreateListNode(4); + ListNode* pNode5 = CreateListNode(5); + + ConnectListNodes(pNode1, pNode2); + ConnectListNodes(pNode2, pNode3); + ConnectListNodes(pNode3, pNode4); + ConnectListNodes(pNode4, pNode5); + + Test(pNode1, pNode5); + + DestroyList(pNode1); +} + +// 链表中有多个结点,删除头结点 +void Test3() +{ + ListNode* pNode1 = CreateListNode(1); + ListNode* pNode2 = CreateListNode(2); + ListNode* pNode3 = CreateListNode(3); + ListNode* pNode4 = CreateListNode(4); + ListNode* pNode5 = CreateListNode(5); + + ConnectListNodes(pNode1, pNode2); + ConnectListNodes(pNode2, pNode3); + ConnectListNodes(pNode3, pNode4); + ConnectListNodes(pNode4, pNode5); + + Test(pNode1, pNode1); + + DestroyList(pNode1); +} + +// 链表中只有一个结点,删除头结点 +void Test4() +{ + ListNode* pNode1 = CreateListNode(1); + + Test(pNode1, pNode1); +} + +// 链表为空 +void Test5() +{ + Test(nullptr, nullptr); +} + +int main(int argc, char* argv[]) +{ + Test1(); + Test2(); + Test3(); + Test4(); + Test5(); + + return 0; +} diff --git "a/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/python/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.py" "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/python/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/python/018_01-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/readme.md" "b/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/readme.md" new file mode 100644 index 0000000..889f007 --- /dev/null +++ "b/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/readme.md" @@ -0,0 +1,82 @@ +# 018_02-在O(1)时间删除链表结点 + +tags: 链表 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/fc533c45b73a41b0b44ccba763f866ef?tpId=13&tqId=11209&tPage=3&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +> 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 + +例如,链表1->2->3->3->4->4->5 + +处理后为 1->2->5 + +## 解题思路 + +我们的思路是, + +1. 我们每次都判断当前结点的值与下一个节点的值是否重复 +2. 如果重复就循环寻找下一个不重复的节点, 将他们链接新新链表的尾部(其实就是删除重复的节点) + +## 代码 + +### [c++代码](./src/cpp/018_02-在O(1)时间删除链表结点.cpp) + +```c++ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +}; +*/ +class Solution { +public: + ListNode* deleteDuplication(ListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + ListNode* node=pHead; + ListNode* front=nullptr; + ListNode* pnext; + + while(node!=nullptr){ + bool needDel=false; + pnext=node->next; + if(pnext!=nullptr&&node->val==pnext->val) + needDel=true; + if(!needDel){ + front=node; + node=pnext; + }else{ + int val=node->val; + ListNode* toDel=node; + while(toDel!=nullptr&&toDel->val==val){ + pnext=toDel->next; + delete toDel; + toDel=nullptr; + toDel=pnext; + } + if(front==nullptr) + pHead=pnext; + else + front->next=pnext; + node=pnext; + } + } + + return pHead; + } +}; +``` + +### [python代码](./src/python/018_02-在O(1)时间删除链表结点.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/cpp/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.cpp" "b/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/cpp/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.cpp" new file mode 100644 index 0000000..e269007 --- /dev/null +++ "b/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/cpp/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.cpp" @@ -0,0 +1,47 @@ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +}; +*/ +class Solution { +public: + ListNode* deleteDuplication(ListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + ListNode* node=pHead; + ListNode* front=nullptr; + ListNode* pnext; + + while(node!=nullptr){ + bool needDel=false; + pnext=node->next; + if(pnext!=nullptr&&node->val==pnext->val) + needDel=true; + if(!needDel){ + front=node; + node=pnext; + }else{ + int val=node->val; + ListNode* toDel=node; + while(toDel!=nullptr&&toDel->val==val){ + pnext=toDel->next; + delete toDel; + toDel=nullptr; + toDel=pnext; + } + if(front==nullptr) + pHead=pnext; + else + front->next=pnext; + node=pnext; + } + } + + return pHead; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/python/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.py" "b/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/python/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271/src/python/018_02-\345\234\250O(1)\346\227\266\351\227\264\345\210\240\351\231\244\351\223\276\350\241\250\347\273\223\347\202\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/img/readme.assets/basis_52_1.png" "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/img/readme.assets/basis_52_1.png" new file mode 100644 index 0000000..04d2033 Binary files /dev/null and "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/img/readme.assets/basis_52_1.png" differ diff --git "a/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/readme.md" "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/readme.md" new file mode 100644 index 0000000..ba0bd92 --- /dev/null +++ "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/readme.md" @@ -0,0 +1,115 @@ +# 019-正则表达式匹配 + +tags:递归 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=3) + +> 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配 + +**样例输入** + +> "a","ab*a" + +**样例输出** + +> false + +## 解题思路 + +[参考](https://github.com/Jack-Cherish/LeetCode) + +这道题有些绕,需要好好思考下。 + +我们先来分析下如何匹配一个字符,现在只考虑字符'.',不考虑'*'看一下: + +如果字符串和模式串的当前字符相等,那么我们继续匹配它们的下一个字符;如果模式串中的字符是'.',那么它可以匹配字符串中的任意字符,我们也可以继续匹配它们的下一个字符。 + +接下来,把字符'*'考虑进去,它可以匹配任意次的字符,当然出现0次也可以。 + +我们分两种情况来看: + +- 模式串的下一个字符不是'*',也就是上面说的只有字符'.'的情况。 + +如果字符串中的第一个字符和模式串中的第一个字符相匹配,那么字符串的模式串都向后移动一个字符,然后匹配剩余的字符串和模式串。如果字符串中的第一个字符和模式中的第一个字符不相匹配,则直接返回false。 + +- 模式串的下一个字符是'*',此时就要复杂一些。 + +因为可能有多种不同的匹配方式。 + +选择一:无论字符串和模式串当前字符相不相等,我们都将模式串后移两个字符,相当于把模式串中的当前字符和'*'忽略掉,因为'*'可以匹配任意次的字符,所以出现0次也可以。 + +选择二:如果字符串和模式串当前字符相等,则字符串向后移动一个字符。而模式串此时有两个选择: + +1、我们可以在模式串向后移动两个字符,继续匹配; + +2、也可以保持模式串不变,这样相当于用字符'*'继续匹配字符串,也就是模式串中的字符'*'匹配字符串中的字符多个的情况。 + +用一张图表示如下: + +[![剑指Offer(五十二):正则表达式匹配](img/readme.assets/basis_52_1.png)](https://cuijiahua.com/wp-content/uploads/2018/01/basis_52_1.png) + +如上图所示,当匹配进入状态2,并且字符串中的字符是'a'时,我们有两个选择:可以进入状态3(在模式串向后移动两个字符),也可以回到状态2(模式串保持不变)。 + +除此之外,还要注意对空指针的处理。 + +#### 代码思路 + +1. 两个字符串都为空,返回true +2. 当第一个字符串不空,而第二个字符串空了,返回false(因为这样,就无法匹配成功了,而如果第一个字符串空了,第二个字符串非空,还是可能匹配成功的,比如第二个字符串是“a*a*a*a*”,由于‘*’之前的元素可以出现0次,所以有可能匹配成功) +3. 开始匹配第一个字符,这里有两种可能:匹配成功或匹配失败。但考虑到pattern下一个字符可能是‘*’, 这里我们分两种情况讨论:pattern下一个字符为‘*’或不为‘*’: + +3.1 pattern下一个字符为‘*’时,稍微复杂一些,因为‘*’可以代表0个或多个。这里把这些情况都考虑到: + +(a) a>当‘*’匹配0个字符时,str当前字符不变,pattern当前字符后移两位,跳过这个‘*’符号; + +(b) >当‘*’匹配1个或多个时,str当前字符移向下一个,pattern当前字符不变; 或者str+1,pattern+2;或者str不变, patter+2; + +3.2 pattern下一个字符不为‘*’:这种情况比较简单,直接匹配当前字符。如果匹配成功,继续匹配下一个;如果匹配失败,直接返回false。注意这里的 “匹配成功”,除了两个字符相同的情况外,还有一种情况,就是pattern的当前字符为‘.’,同时str的当前字符不为‘\0’。 + +## 代码 + +### [c++代码](./src/cpp/019-正则表达式匹配.cpp) + +```c++ + + +class Solution { +public: + bool match(char* str, char* pattern) + { + if(str==nullptr||pattern==nullptr) + return false; + else + return matchCore(str,pattern); + } + + bool matchCore(char* str, char* pattern){ + if(*str=='\0'&&*pattern=='\0') + return true; + if(*str!='\0'&&*pattern=='\0') + return false; + if(*(pattern+1)=='*'){ + if(*str==*pattern||(*pattern=='.'&&*str!='\0')) + return matchCore(str+1,pattern+2)||matchCore(str+1,pattern)||matchCore(str,pattern+2); + else + return matchCore(str,pattern+2); + } + if(*str==*pattern||(*pattern=='.'&&*str!='\0')){ + return matchCore(str+1,pattern+1); + } + + return false; + } +}; +``` + +### [python代码](./src/python/019-正则表达式匹配.py) + +```python + +``` + diff --git "a/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/src/cpp/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.cpp" "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/src/cpp/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.cpp" new file mode 100644 index 0000000..b51e6f0 --- /dev/null +++ "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/src/cpp/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.cpp" @@ -0,0 +1,30 @@ + + +class Solution { +public: + bool match(char* str, char* pattern) + { + if(str==nullptr||pattern==nullptr) + return false; + else + return matchCore(str,pattern); + } + + bool matchCore(char* str, char* pattern){ + if(*str=='\0'&&*pattern=='\0') + return true; + if(*str!='\0'&&*pattern=='\0') + return false; + if(*(pattern+1)=='*'){ + if(*str==*pattern||(*pattern=='.'&&*str!='\0')) + return matchCore(str+1,pattern+2)||matchCore(str+1,pattern)||matchCore(str,pattern+2); + else + return matchCore(str,pattern+2); + } + if(*str==*pattern||(*pattern=='.'&&*str!='\0')){ + return matchCore(str+1,pattern+1); + } + + return false; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/src/python/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/src/python/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215/src/python/019-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\214\271\351\205\215.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/readme.md" "b/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/readme.md" new file mode 100644 index 0000000..90e7f23 --- /dev/null +++ "b/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/readme.md" @@ -0,0 +1,123 @@ +# 020-表示数值的字符串 + +tags: 字符串 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/6f8c901d091949a5837e24bb82a731f2?tpId=13&tqId=11206&tPage=3&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。 + +## 解题思路 + +### 思路一 借助几个flag从头到尾遍历 + +[参考](https://www.nowcoder.com/questionTerminal/6f8c901d091949a5837e24bb82a731f2) + +```c++ +class Solution { +public: + bool isNumeric(char* str) { + // 标记符号、小数点、e是否出现过 + bool sign = false, decimal = false, hasE = false; + for (int i = 0; i < strlen(str); i++) { + if (str[i] == 'e' || str[i] == 'E') { + if (i == strlen(str)-1) return false; // e后面一定要接数字 + if (hasE) return false; // 不能同时存在两个e + hasE = true; + } else if (str[i] == '+' || str[i] == '-') { + // 第二次出现+-符号,则必须紧接在e之后 + if (sign && str[i-1] != 'e' && str[i-1] != 'E') return false; + // 第一次出现+-符号,且不是在字符串开头,则也必须紧接在e之后 + if (!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E') return false; + sign = true; + } else if (str[i] == '.') { + // e后面不能接小数点,小数点不能出现两次 + if (hasE || decimal) return false; + decimal = true; + } else if (str[i] < '0' || str[i] > '9') // 不合法字符 + return false; + } + return true; + } +}; +``` + +### 思路2 + +从头到尾遍历,对遇到的不同情况进行分析,但很容易出错。因此采用《剑指OFFER》一书的方法:将数字的形式总结为:(A.B E/e A) ,按顺序进行判断(A代表带符号整数,B代表不带符号整数)。 + + + +## 代码 + +### [c++代码](./src/cpp/020-表示数值的字符串.cpp) + +#### 易错点 + +- `const char** str` +- `scanUnsignedInteger(&str) || numeric` 二者的顺序不可以调换, 因为c++中, ||左面为true, 右边的就不执行了; &&左边为false, 右边的就不执行了. + +```c++ +// 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是 +// 整数(可以有正负号,也可以没有),而B是一个无符号整数 +bool isNumeric(const char* str) +{ + if(str == nullptr) + return false; + + bool numeric = scanInteger(&str); + + // 如果出现'.',接下来是数字的小数部分 + if(*str == '.') + { + ++str; + + // 下面一行代码用||的原因: + // 1. 小数可以没有整数部分,例如.123等于0.123; + // 2. 小数点后面可以没有数字,例如233.等于233.0; + // 3. 当然小数点前面和后面可以有数字,例如233.666 + numeric = scanUnsignedInteger(&str) || numeric; + } + + // 如果出现'e'或者'E',接下来跟着的是数字的指数部分 + if(*str == 'e' || *str == 'E') + { + ++str; + + // 下面一行代码用&&的原因: + // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1; + // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4 + numeric = numeric && scanInteger(&str); + } + + return numeric && *str == '\0'; +} + +bool scanUnsignedInteger(const char** str) +{ + const char* before = *str; + while(**str != '\0' && **str >= '0' && **str <= '9') + ++(*str); + + // 当str中存在若干0-9的数字时,返回true + return *str > before; +} + +// 整数的格式可以用[+|-]B表示, 其中B为无符号整数 +bool scanInteger(const char** str) +{ + if(**str == '+' || **str == '-') + ++(*str); + return scanUnsignedInteger(str); +} +``` + +### [python代码](./src/python/020-表示数值的字符串.py) + +```python + +``` + diff --git "a/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/src/cpp/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.cpp" "b/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/src/cpp/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.cpp" new file mode 100644 index 0000000..4d53f38 --- /dev/null +++ "b/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/src/cpp/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.cpp" @@ -0,0 +1,52 @@ +// 数字的格式可以用A[.[B]][e|EC]或者.B[e|EC]表示,其中A和C都是 +// 整数(可以有正负号,也可以没有),而B是一个无符号整数 +bool isNumeric(const char* str) +{ + if(str == nullptr) + return false; + + bool numeric = scanInteger(&str); + + // 如果出现'.',接下来是数字的小数部分 + if(*str == '.') + { + ++str; + + // 下面一行代码用||的原因: + // 1. 小数可以没有整数部分,例如.123等于0.123; + // 2. 小数点后面可以没有数字,例如233.等于233.0; + // 3. 当然小数点前面和后面可以有数字,例如233.666 + numeric = scanUnsignedInteger(&str) || numeric; + } + + // 如果出现'e'或者'E',接下来跟着的是数字的指数部分 + if(*str == 'e' || *str == 'E') + { + ++str; + + // 下面一行代码用&&的原因: + // 1. 当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1; + // 2. 当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4 + numeric = numeric && scanInteger(&str); + } + + return numeric && *str == '\0'; +} + +bool scanUnsignedInteger(const char** str) +{ + const char* before = *str; + while(**str != '\0' && **str >= '0' && **str <= '9') + ++(*str); + + // 当str中存在若干0-9的数字时,返回true + return *str > before; +} + +// 整数的格式可以用[+|-]B表示, 其中B为无符号整数 +bool scanInteger(const char** str) +{ + if(**str == '+' || **str == '-') + ++(*str); + return scanUnsignedInteger(str); +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/src/python/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.py" "b/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/src/python/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262/src/python/020-\350\241\250\347\244\272\346\225\260\345\200\274\347\232\204\345\255\227\347\254\246\344\270\262.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/readme.md" "b/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/readme.md" new file mode 100644 index 0000000..1d5e6d9 --- /dev/null +++ "b/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/readme.md" @@ -0,0 +1,236 @@ +# 021-调整数组顺序使奇数位于偶数前面 + +tags: 稳定排序 两指针 + +--- + +## 剑指offer题目 不要求稳定 + +### 题目原文 + +输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。 + +### 解题思路 + +由于题目中只要求记奇数在偶数之前,那么我们在扫描这个数组的时候,如果发现一个偶数出现在奇数之前就交换他们的位置,这样一趟后就满足要求了。 + +因此我们 + +- 维护两个索引或者指针,一个指向数组的第一个元素,并向后移动,一个指向数组的最后一个元素,并向前移动。 +- 如果第一个指针指向的元素是偶数,而第二个指针指向的元素是奇数,说明偶数在奇数前面,那么就交换这两个数。 +- 直到两个指针相遇为止 + +```c++ + void reOrderArray(vector &array) + { + if(array.size( ) <= 1) + { + return ; + } + vector::iterator left = array.begin( ); + vector::iterator right = array.end( ) - 1; + + // 三种顺序容器中只有deque和vector容器的迭代器支持大小的比较和算术运算。 + + while(left < right) + { + + // left向后移动指向第一个偶数 + while(left < right && (*left & 0x01) == 1) + { + left++; + } + + // right向前移动指向第一个奇数 + while(left < right && (*right &0x01) == 0) + { + right--; + } + + if(left < right) + { + swap(*left, *right); + } + } + + } +``` + +## 牛客网题目 + +[题目链接](https://www.nowcoder.com/practice/beb5aa231adc45b2a5dcc5b62c93f593?tpId=13&tqId=11166&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +### 题目原文 + +输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 + +与剑指offer题目不同的是, 这道题要求`奇数和奇数,偶数和偶数之间的相对位置不变`, 类似于排序中的稳定性 + +### 稳定性定义 + +算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的! + +### 解题思路1 使用稳定排序算法 + +从题目得出的信息: + +相对位置不变--->保持稳定性;奇数位于前面,偶数位于后面 --->存在判断,挪动元素位置; + +这些都和内部排序算法相似,考虑到具有稳定性的排序算法不多,例如插入排序,归并排序等; + +采用冒泡排的思想实现: + +每次循环前偶后奇就交换, 同时我们设立一个标识,来标识数组是否已经符合要求 + +当再次循环时,发现没有要交换的数据,说明数组已经符合要求 + +```c++ + void reOrderArray(vector &array) + { + if(array.size( ) <= 1) + { + return ; + } + bool isSwap = false; + for (int i = 0; i < array.size( ); i++) + { + isSwap = false; + for (int j = array.size() - 1; j > i; j--) + { + if (array[j] % 2 == 1 && array[j - 1]%2 == 0) //前偶后奇交换 + { + swap(array[j], array[j-1]); + isSwap = true; + } + } + if(isSwap == false) + { + break; + } + } + + + } +``` + + + +采用插入排的思想实现: + +```c++ +public class Solution { + public void reOrderArray(int [] array) { + //相对位置不变,稳定性 + //插入排序的思想 + int m = array.length; + int k = 0;//记录已经摆好位置的奇数的个数 + for (int i = 0; i < m; i++) { + if (array[i] % 2 == 1) { + int j = i; + while (j > k) {//j >= k+1 + int tmp = array[j]; + array[j] = array[j-1]; + array[j-1] = tmp; + j--; + } + k++; + } + } + } +} +``` + + + +### 思路2 辅助数组完成 + +我们也可以利用一个辅助的数组空间来实现 + +- 在原来的数组中遇到偶数就放进新数组中,然后将该偶数从原来数组中删除,当整个遍历结束后,原来数组中只剩下奇数,新的数组总只剩下偶数,最后我们将新的数组追加在原来数组的末尾即可 + +```c++ + void reOrderArray(vector &array) + { + if(array.size( ) <= 1) + { + return ; + } + + vector array_temp; + vector::iterator ib1, ie1; + ib1 = array.begin(); + + + for (; ib1 != array.end();) + { //遇见偶数,就保存到新数组,同时从原数组中删除 + if (*ib1 % 2 == 0) + { + array_temp.push_back(*ib1); + ib1 = array.erase(ib1); + } + else{ + ib1++; + } + + } + vector::iterator ib2, ie2; + ib2 = array_temp.begin(); + ie2 = array_temp.end(); + + for (; ib2 != ie2; ib2++) //将新数组的数添加到老数组 + { + array.push_back(*ib2); + } + } +``` + +### 思路3 STL + +STL stable_partition 这个函数 + +函数功能是将数组中 isOk为真的放在数组前,假的放在数组后,和题意相符 + +````c++ +stable_partition(array.begin(), array.end(), [](int i){return i % 2 == 1;}); +```` + + + +## 代码 + +### [c++代码](./src/cpp/021-调整数组顺序使奇数位于偶数前面.cpp) + +```c++ + void reOrderArray(vector &array) + { + if(array.size( ) <= 1) + { + return ; + } + bool isSwap = false; + for (int i = 0; i < array.size( ); i++) + { + isSwap = false; + for (int j = array.size() - 1; j > i; j--) + { + if (array[j] % 2 == 1 && array[j - 1]%2 == 0) //前偶后奇交换 + { + swap(array[j], array[j-1]); + isSwap = true; + } + } + if(isSwap == false) + { + break; + } + } + + + } +``` + +### [python代码](./src/python/021-调整数组顺序使奇数位于偶数前面.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/src/cpp/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.cpp" "b/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/src/cpp/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.cpp" new file mode 100644 index 0000000..5a01102 --- /dev/null +++ "b/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/src/cpp/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.cpp" @@ -0,0 +1,26 @@ + void reOrderArray(vector &array) + { + if(array.size( ) <= 1) + { + return ; + } + bool isSwap = false; + for (int i = 0; i < array.size( ); i++) + { + isSwap = false; + for (int j = array.size() - 1; j > i; j--) + { + if (array[j] % 2 == 1 && array[j - 1]%2 == 0) //前偶后奇交换 + { + swap(array[j], array[j-1]); + isSwap = true; + } + } + if(isSwap == false) + { + break; + } + } + + + } \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/src/python/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.py" "b/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/src/python/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242/src/python/021-\350\260\203\346\225\264\346\225\260\347\273\204\351\241\272\345\272\217\344\275\277\345\245\207\346\225\260\344\275\215\344\272\216\345\201\266\346\225\260\345\211\215\351\235\242.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/img/readme.assets/1562038903131.png" "b/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/img/readme.assets/1562038903131.png" new file mode 100644 index 0000000..6a2f6d9 Binary files /dev/null and "b/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/img/readme.assets/1562038903131.png" differ diff --git "a/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/readme.md" "b/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/readme.md" new file mode 100644 index 0000000..a9ba4fa --- /dev/null +++ "b/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/readme.md" @@ -0,0 +1,199 @@ +# 022-链表中倒数第k个结点 + +tags: 两支针 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一个链表,输出该链表中倒数第k个结点。 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/015-%E9%93%BE%E8%A1%A8%E4%B8%AD%E5%80%92%E6%95%B0%E7%AC%ACk%E4%B8%AA%E7%BB%93%E7%82%B9](https://github.com/gatieme/CodingInterviews/tree/master/015-链表中倒数第k个结点)) + +这道题我想大多数人都会有思路,因为我们已经见的很多了 最暴力的方式,两趟遍历,第一趟先求出list的长度length,然后进而length - k得到倒数第k个节点的位置 当然我们大多数都会知道另外一个更加高效的方法,**双指针法** 其实就是第一个指针right先向前走K步,然后left和right一起走,此时两个指针差别K步,那么当right走到链表尾部的时候,left指向的就是倒数第K个节点 + +期间要注意的问题有 + +- 链表可能为NULL +- 链表长度可能没有K个 +- 输入参数k是unsigned int,当k为0时, for循环中k-1得到的不是-1, 而是4294967295(无符号的0XFFFFFFFF), for循环次数会超出预计, 造成程序崩溃. + +```c++ +/// 1 -> 2 -> 3 -> 4 -> 5 +/// 比如要走倒数第3个节点 +/// 那么right先走到第3 - 1个节点&[2] +/// 那么right指针向前走到其下一个节点为NULL时, left节点既是倒数第K个节点 +/// 此时两个指针相差为K - 1 + + +/// 1 -> 2 -> 3 -> 4 -> 5 +/// 比如要走倒数第3个节点 +/// 那么right先走到第3个节点&[2] +/// 那么right指针向前走到链表尾部为NULL时, left节点既是倒数第K个节点 +/// 此时两个指针相差为K +class Solution +{ +public: + ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) + { + if(pListHead == NULL) + { + return NULL; + } + unsigned int i = 0; + ListNode *right = pListHead; + + // left指针先向前走K步 + while(i < k && right != NULL) + { + debug <<"index = " <next != NULL) + { + debug <<"index = " <next!=nullptr) + fast=fast->next; + else + return nullptr; + + } + + while(fast->next!=nullptr){ + fast=fast->next; + low=low->next; + } + + return low; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/src/python/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271.py" "b/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/src/python/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271/src/python/022-\351\223\276\350\241\250\344\270\255\345\200\222\346\225\260\347\254\254k\344\270\252\347\273\223\347\202\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/4240377_1529033184336_9A253E69EDBB4FD57BB16FC3A32C2756.jpg" "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/4240377_1529033184336_9A253E69EDBB4FD57BB16FC3A32C2756.jpg" new file mode 100644 index 0000000..9e20cfa Binary files /dev/null and "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/4240377_1529033184336_9A253E69EDBB4FD57BB16FC3A32C2756.jpg" differ diff --git "a/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/basis_55_1.png" "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/basis_55_1.png" new file mode 100644 index 0000000..2cf9335 Binary files /dev/null and "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/basis_55_1.png" differ diff --git "a/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/\345\276\256\344\277\241\345\233\276\347\211\207_20190702172216.jpg" "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/\345\276\256\344\277\241\345\233\276\347\211\207_20190702172216.jpg" new file mode 100644 index 0000000..05a6aa9 Binary files /dev/null and "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/img/readme.assets/\345\276\256\344\277\241\345\233\276\347\211\207_20190702172216.jpg" differ diff --git "a/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/readme.md" "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/readme.md" new file mode 100644 index 0000000..7b0a7a8 --- /dev/null +++ "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/readme.md" @@ -0,0 +1,284 @@ +# 023-链表中环的入口结点 + +tags: 两指针 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&tqId=11208&tPage=3&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。 + +## 解题思路 + +### 剑指offer + +假设链表长度为N, 那么第N链接到了第k个节点形成了环,即我们需要查找到倒数第N-K+1个节点, 那么环中就有N-K+1个节点,这时候我们定义两个指针$P_1$和$P_2$指向链表的头部, 指针$P_1$先在链表中向前移动n-k+1步,到达第n-k+2个节点, 然后两个指针同步向前移动, 当$P_2$走了K-1步到达环的入口的时候, 指针$P_1$正好走了N+1步, 到达了环的入口, 即两个指针会相遇在环的入口处 + +以下图为例,指针P1和P2在初始化时都指向链表的头结点。由于环中有4个结点,指针P1先在链表上向前移动4步。接下来两个指针以相同的速度在链表上向前移动,直到它们相遇。它们相遇的结点正好是环的入口结点。 + +![剑指Offer(五十五):链表中环的入口结点](img/readme.assets/basis_55_1.png) + +那么我们剩下的问题就是如何得到环中节点的数目? + +我们可以使用一快一慢两个指针(比如慢指针一次走一步, 慢指针一次走两步),如果走的过程中发现快指针追上了慢指针, 说明遇见了环,而且相遇的位置一定在环内, 考虑一下环内, 从任何一个节点出现再回到这个节点的距离就是环的长度, 于是我们可以进一步移动慢指针,快指针原地不动, 当慢指针再次回到相遇位置时, 正好在环内走了一圈, 从而我们通过计数就可以获取到环的长度 + +- 第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。 +- 第二步,找环的长度。从环中的相汇点开始, p2不动, p1前移, 当再次相遇时,p1刚好绕环一周, 其移动即为环的长度K +- 第三步, 求换的起点, 转换为求环的倒数第N-K个节点,则两指针left和right均指向起始, right先走K步, 然后两个指针开始同步移动, 当两个指针再次相遇时, right刚好绕环一周回到起点, left则刚好走到了起点位置 + +![微信图片_20190702172216](img/readme.assets/微信图片_20190702172216.jpg) + +```c++ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +}; +*/ +class Solution { +public: + ListNode* EntryNodeOfLoop(ListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + ListNode* meetingNode=FindMeetingNode(pHead); + if(meetingNode==nullptr) + return nullptr; + ListNode* p1=meetingNode->next; + int num=1; + while(p1!=meetingNode){ + p1=p1->next; + num++; + } + + ListNode* p2=pHead; + + while(num>0){ + p2=p2->next; + num--; + } + + p1=pHead; + + while(p1!=p2){ + p1=p1->next; + p2=p2->next; + } + + return p1; + } + + ListNode* FindMeetingNode(ListNode* pHead){ + if(pHead==nullptr||pHead->next==nullptr) + return nullptr; + ListNode* slow=pHead; + ListNode* fast=slow->next; + + while(slow!=nullptr&&fast!=nullptr){ + if(slow==fast) + return slow; + slow=slow->next; + fast=fast->next; + if(fast!=nullptr) + fast=fast->next; + } + return nullptr; + } +}; +``` + +### 稍微简单一些的办法 + +[参考](https://www.acwing.com/solution/acwing/content/741/) + +[参考](https://www.e-learn.cn/content/qita/780537) + +两个结论: + +​ **1、设置快慢指针,假如有环,他们最后一定相遇。** + +​ **2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。** + +​ **证明1**:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。 + +​ **证明2:** + +​ 设: + +​ 链表头到环入口长度为--**a** + +​ 环入口到相遇点长度为--**b** + +​ 相遇点到环入口长度为--**c** + + + +![img](img/readme.assets/4240377_1529033184336_9A253E69EDBB4FD57BB16FC3A32C2756.jpg) + +则:相遇时 + +​ **快指针路程=a+(b+c)k+b** ,k>=1 其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。 + +​ **慢指针路程=a+b** + +​ 快指针走的路程是慢指针的两倍,所以: + +​ **(a+b)\*2=a+(b+c)k+b** + +​ 化简可得: + +​ **a=(k-1)(b+c)+c** 这个式子的意思是: **链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度**。其中k>=1,所以**k-1>=0**圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。 + +```c++ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode *entryNodeOfLoop(ListNode *head) { + if (!head || !head->next) return 0; + ListNode *first = head, *second = head; + + while (first && second) + { + first = first->next; + second = second->next; + if (second) second = second->next; + else return 0; + + if (first == second) + { + first = head; + while (first != second) + { + first = first->next; + second = second->next; + } + return first; + } + } + + return 0; + } +}; + +``` + +### 断链法 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/056-%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%8E%AF%E7%9A%84%E5%85%A5%E5%8F%A3%E7%BB%93%E7%82%B9](https://github.com/gatieme/CodingInterviews/tree/master/056-链表中环的入口结点)) + +时间复杂度为O(n),两个指针,一个在前面,另一个紧邻着这个指针,在后面。 两个指针同时向前移动,每移动一次,前面的指针的next指向NULL。 也就是说:访问过的节点都断开,最后到达的那个节点一定是尾节点的下一个, 也就是循环的第一个。 这时候已经是第二次访问循环的第一节点了,第一次访问的时候我们已经让它指向了NULL, 所以到这结束。 + +但是这种方法修改了链表的指向 + +```c++ +class Solution +{ +public: + ListNode* EntryNodeOfLoop(ListNode* pHead) + { + if (pHead == NULL + || pHead->next == NULL) + { + return NULL; + } + + ListNode* previous = pHead; + ListNode* current = pHead->next; + while (current != NULL) + { + previous->next = NULL; + previous = current; + current = current->next; + } + + return previous; + } +}; +``` + + + +## 代码 + +### [c++代码](./src/cpp/023-链表中环的入口结点.cpp) + +```c++ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +}; +*/ +class Solution { +public: + ListNode* EntryNodeOfLoop(ListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + ListNode* meetingNode=FindMeetingNode(pHead); + if(meetingNode==nullptr) + return nullptr; + ListNode* p1=meetingNode->next; + int num=1; + while(p1!=meetingNode){ + p1=p1->next; + num++; + } + + ListNode* p2=pHead; + + while(num>0){ + p2=p2->next; + num--; + } + + p1=pHead; + + while(p1!=p2){ + p1=p1->next; + p2=p2->next; + } + + return p1; + } + + ListNode* FindMeetingNode(ListNode* pHead){ + if(pHead==nullptr||pHead->next==nullptr) + return nullptr; + ListNode* slow=pHead; + ListNode* fast=slow->next; + + while(slow!=nullptr&&fast!=nullptr){ + if(slow==fast) + return slow; + slow=slow->next; + fast=fast->next; + if(fast!=nullptr) + fast=fast->next; + } + return nullptr; + } +}; +``` + +### [python代码](./src/python/023-链表中环的入口结点.py) + +```python + +``` + diff --git "a/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/src/cpp/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271.cpp" "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/src/cpp/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271.cpp" new file mode 100644 index 0000000..186b6d3 --- /dev/null +++ "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/src/cpp/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271.cpp" @@ -0,0 +1,59 @@ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +}; +*/ +class Solution { +public: + ListNode* EntryNodeOfLoop(ListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + ListNode* meetingNode=FindMeetingNode(pHead); + if(meetingNode==nullptr) + return nullptr; + ListNode* p1=meetingNode->next; + int num=1; + while(p1!=meetingNode){ + p1=p1->next; + num++; + } + + ListNode* p2=pHead; + + while(num>0){ + p2=p2->next; + num--; + } + + p1=pHead; + + while(p1!=p2){ + p1=p1->next; + p2=p2->next; + } + + return p1; + } + + ListNode* FindMeetingNode(ListNode* pHead){ + if(pHead==nullptr||pHead->next==nullptr) + return nullptr; + ListNode* slow=pHead; + ListNode* fast=slow->next; + + while(slow!=nullptr&&fast!=nullptr){ + if(slow==fast) + return slow; + slow=slow->next; + fast=fast->next; + if(fast!=nullptr) + fast=fast->next; + } + return nullptr; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/src/python/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271.py" "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/src/python/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271/src/python/023-\351\223\276\350\241\250\344\270\255\347\216\257\347\232\204\345\205\245\345\217\243\347\273\223\347\202\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/readme.md" "b/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/readme.md" new file mode 100644 index 0000000..3d445d3 --- /dev/null +++ "b/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/readme.md" @@ -0,0 +1,74 @@ +# 024-反转链表 + +tags: 链表 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=13&tqId=11168&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一个链表,反转链表后,输出链表的所有元素。 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/016-%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8](https://github.com/gatieme/CodingInterviews/tree/master/016-反转链表)) + +三指针滑动pPrev -> pNode -> pNext; + +通常我们想到的就是单个指针同时滑动 比如当前节点pNode所处的位置如下 + +> pPrev -> pNode -> pNext; 我们先保存原来的下一个指针位置,要不然翻转后其next会指向pPrev,从而丢失指向pNext的指针 接着反转指针, 然后下面指针同步后移,以便处理后面的指针 + +``` +pNext = pNode->next; // 保存其下一个节点 +pNode->next = pPrev; // 指针指向反转 +// 下面开始指针的后移 +pPrev = pNode; // 保存前一个指针 +pNode = pNext; // 递增指针, 指向下一个结点 +``` + + + +## 代码 + +### [c++代码](./src/cpp/024-反转链表.cpp) + +```c++ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +};*/ +class Solution { +public: + ListNode* ReverseList(ListNode* pHead) { + if(pHead==nullptr) + return nullptr; + ListNode* pReservedHead=nullptr; + ListNode* pNode=pHead; + ListNode* pPre=nullptr; + ListNode* pNext=nullptr; + while(pNode!=nullptr){ + pNext=pNode->next; + if(pNext==nullptr){ + pReservedHead=pNode; + } + pNode->next=pPre; + pPre=pNode; + pNode=pNext; + } + return pReservedHead; + } +}; +``` + +### [python代码](./src/python/024-反转链表.py) + +```python + +``` + diff --git "a/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/src/cpp/024-\345\217\215\350\275\254\351\223\276\350\241\250.cpp" "b/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/src/cpp/024-\345\217\215\350\275\254\351\223\276\350\241\250.cpp" new file mode 100644 index 0000000..9a8af96 --- /dev/null +++ "b/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/src/cpp/024-\345\217\215\350\275\254\351\223\276\350\241\250.cpp" @@ -0,0 +1,29 @@ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +};*/ +class Solution { +public: + ListNode* ReverseList(ListNode* pHead) { + if(pHead==nullptr) + return nullptr; + ListNode* pReservedHead=nullptr; + ListNode* pNode=pHead; + ListNode* pPre=nullptr; + ListNode* pNext=nullptr; + while(pNode!=nullptr){ + pNext=pNode->next; + if(pNext==nullptr){ + pReservedHead=pNode; + } + pNode->next=pPre; + pPre=pNode; + pNode=pNext; + } + return pReservedHead; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/src/python/024-\345\217\215\350\275\254\351\223\276\350\241\250.py" "b/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/src/python/024-\345\217\215\350\275\254\351\223\276\350\241\250.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/024-\345\217\215\350\275\254\351\223\276\350\241\250/src/python/024-\345\217\215\350\275\254\351\223\276\350\241\250.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/readme.md" "b/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/readme.md" new file mode 100644 index 0000000..00935a1 --- /dev/null +++ "b/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/readme.md" @@ -0,0 +1,77 @@ +# 025-合并两个排序的链表 + +tags: 链表 递归 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337?tpId=13&tqId=11169&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 + +## 解题思路 + +[参考](https://cuijiahua.com/blog/2017/12/basis_16.html) + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/017-%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%8E%92%E5%BA%8F%E7%9A%84%E9%93%BE%E8%A1%A8](https://github.com/gatieme/CodingInterviews/tree/master/017-合并两个排序的链表)) + +### 常规解法 + +用两个指针同步遍历两个链表,每次找到小的那个插入到新的链表中 + +### 递归解法 + +先判断输入的链表是否为空的指针。如果第一个链表为空,则直接返回第二个链表;如果第二个链表为空,则直接返回第一个链表。如果两个链表都是空链表,合并的结果是得到一个空链表。 + +两个链表都是排序好的,我们只需要从头遍历链表,判断当前指针,哪个链表中的值小,即赋给合并链表指针即可。使用递归就可以轻松实现。 + +其实这道题跟LeetCode上一道题是一样的 + +[LeetCodet题解--21. Merge Two Sorted Lists(合并两个排序好的链表)](http://blog.csdn.net/gatieme/article/details/51094742) + +当然他还有很多变种,比如说两个链表扩展成为K个的时候 + +[LeetCodet题解--23. Merge k Sorted Lists(合并K个已排序的链表)](http://blog.csdn.net/gatieme/article/details/51097730) + +## 代码 + +### [c++代码](./src/cpp/025-合并两个排序的链表.cpp) + +```c++ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +};*/ +class Solution { +public: + ListNode* Merge(ListNode* pHead1, ListNode* pHead2) + { + ListNode* newHead=nullptr; + if(pHead1==nullptr&&pHead2==nullptr) + return nullptr; + if(pHead1==nullptr) + return pHead2; + if(pHead2==nullptr) + return pHead1; + if(pHead1->val<=pHead2->val){ + newHead=pHead1; + newHead->next=Merge(pHead1->next,pHead2); + }else{ + newHead=pHead2; + newHead->next=Merge(pHead1,pHead2->next); + } + return newHead; + } +}; +``` + +### [python代码](./src/python/025-合并两个排序的链表.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/src/cpp/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.cpp" "b/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/src/cpp/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.cpp" new file mode 100644 index 0000000..175dd94 --- /dev/null +++ "b/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/src/cpp/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.cpp" @@ -0,0 +1,29 @@ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +};*/ +class Solution { +public: + ListNode* Merge(ListNode* pHead1, ListNode* pHead2) + { + ListNode* newHead=nullptr; + if(pHead1==nullptr&&pHead2==nullptr) + return nullptr; + if(pHead1==nullptr) + return pHead2; + if(pHead2==nullptr) + return pHead1; + if(pHead1->val<=pHead2->val){ + newHead=pHead1; + newHead->next=Merge(pHead1->next,pHead2); + }else{ + newHead=pHead2; + newHead->next=Merge(pHead1,pHead2->next); + } + return newHead; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/src/python/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.py" "b/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/src/python/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250/src/python/025-\345\220\210\345\271\266\344\270\244\344\270\252\346\216\222\345\272\217\347\232\204\351\223\276\350\241\250.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414194200284.jpg" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414194200284.jpg" new file mode 100644 index 0000000..ebd78bc Binary files /dev/null and "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414194200284.jpg" differ diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195320401.jpg" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195320401.jpg" new file mode 100644 index 0000000..68028d6 Binary files /dev/null and "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195320401.jpg" differ diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195403530.jpg" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195403530.jpg" new file mode 100644 index 0000000..4a3157e Binary files /dev/null and "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195403530.jpg" differ diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195548760.jpg" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195548760.jpg" new file mode 100644 index 0000000..4c68eb1 Binary files /dev/null and "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/20180414195548760.jpg" differ diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/381412-20150830202322937-1382013325.jpg" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/381412-20150830202322937-1382013325.jpg" new file mode 100644 index 0000000..2988e49 Binary files /dev/null and "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/381412-20150830202322937-1382013325.jpg" differ diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/997228-20170508165926754-1808360351.png" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/997228-20170508165926754-1808360351.png" new file mode 100644 index 0000000..0b3d5a1 Binary files /dev/null and "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/img/readme.assets/997228-20170508165926754-1808360351.png" differ diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/readme.md" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/readme.md" new file mode 100644 index 0000000..2e39021 --- /dev/null +++ "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/readme.md" @@ -0,0 +1,247 @@ +# 026-树的子结构 + +tags: 二叉树 递归 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88?tpId=13&tqId=11170&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +**题目:**输入两棵二叉树A和B,判断B是不是A的子结构。例如下图中的两棵二叉树,由于A中有一部分子树的结构和B是一样的,因此B是A的子结构。 + +![img](img/readme.assets/381412-20150830202322937-1382013325.jpg) + +## 解题思路 + + [参考](https://www.cnblogs.com/lfeng1205/p/6826026.html) + +要查找树A是否存在和树B结构一样的子树,我们可以分成两步:第一步在树A中找到和树B的根节点的值一样的节点R,第二步再判断树A中以R为根节点的子树是不是包含和树B一样的结构。 + +![img](img/readme.assets/997228-20170508165926754-1808360351.png) + + + +  如上图所示:首先我们试着在树A中找到值为8(树B的根节点的值)的节点。从树A的根节点开始遍历,我们发现它的根节点就是8。接着我们就去判断树A的根节点下面的子树是不是含有和树B一样的结构。在树A中,根节点的左子节点的值是8,而树B的根节点的左子节点是9,对应的两个节点不同。 + +  因此,我们仍需要遍历树A,接着查找值为8的节点。我们在树的第二层找到了一个值为8的节点,然后进行第二步判断,即判断这个节点下面的子树是否含有和树B一样结构的子树。于是我们遍历这个节点下面的子树,先后得到两个子节点9和2,这和B树的结构完全相同。此时我们在树A中找到了一个和树B的结构一样的子树,因此树B是树A的子结构。 + +  第一步在树A中查找与根节点一样的节点,实际上就是树的遍历,可以采用递归的方式,代码如下: + +```c++ + bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + bool res=false; + if(pRoot1!=nullptr&&pRoot2!=nullptr){ + if(pRoot1->val==pRoot2->val) + res=doesTree1HasTree2(pRoot1,pRoot2); + if(!res) + res=doesTree1HasTree2(pRoot1->left,pRoot2); + if(!res) + res=doesTree1HasTree2(pRoot1->right,pRoot2); + } + return res; + } +``` + +第二步是判断树A中以R为根节点的子树是不是和树B具有相同的结构。同样,我们也可以用递归的思路来考虑:如果节点R的值和树B的根节点不相同,则以R为根节点的子树和树B肯定不具有相同的结点;如果它们的值相同,则递归地判断它们各自的左右节点的值是不是相同。递归的终止条件是我们到达了树A或者树B的叶节点,代码如下: + + + ```c++ + bool doesTree1HasTree2(TreeNode* pRoot1, TreeNode* pRoot2){ + if (pRoot2==nullptr) + return true; + if (pRoot1==nullptr) + return false; + if(pRoot1->val!=pRoot2->val) + return false; + return doesTree1HasTree2(pRoot1->left,pRoot2->left)&&doesTree1HasTree2(pRoot1->right,pRoot2->right); + ``` + +上述代码有多处判断节点是不是NULL,这样做是为了避免试图访问空节点而造成的程序崩溃,同时设置了递归调用的退出条件。 + +## 代码 + +### [c++代码](./src/cpp/026-树的子结构.cpp) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + bool res=false; + if(pRoot1!=nullptr&&pRoot2!=nullptr){ + if(pRoot1->val==pRoot2->val) + res=doesTree1HasTree2(pRoot1,pRoot2); + if(!res) + res=doesTree1HasTree2(pRoot1->left,pRoot2); + if(!res) + res=doesTree1HasTree2(pRoot1->right,pRoot2); + } + return res; + } + + bool doesTree1HasTree2(TreeNode* pRoot1, TreeNode* pRoot2){ + if (pRoot2==nullptr) + return true; + if (pRoot1==nullptr) + return false; + if(pRoot1->val!=pRoot2->val) + return false; + return doesTree1HasTree2(pRoot1->left,pRoot2->left)&&doesTree1HasTree2(pRoot1->right,pRoot2->right); + } +}; +``` + +### [python代码](./src/python/026-树的子结构.py) + +```python + +``` + +## 二叉树的子树和子结构 + +[参考](https://blog.csdn.net/wushuomin/article/details/79943737) + +> 子树的意思是只要包含了一个结点,就得包含这个结点下的所有节点. +> 子结构的意思是包含了一个结点,可以只取左子树或者右子树,或者都不取。 + +简单而言,与子树不同的是,子结构可以是A树的任意一部分。 +这里以一颗7节点,高度为3的满二叉树为例,说明子树和子结构的差别: + +![1](img/readme.assets/20180414194200284.jpg) + +**1.图1的子树示意图** +对于图1而言,子树意味着图2,图3等情况。根据定义非常好理解。 + +![2](img/readme.assets/20180414195320401.jpg) + +图2 图1子树的某一种情况 + + + +![3](img/readme.assets/20180414195403530.jpg) + +图3 图1子树的某一种情况 + + + + + +**2.图1的子结构示意图** +由于子结构可以是原树的任意一个部分,因此图3就是一个子结构。 + +![3](img/readme.assets/20180414195548760.jpg) + +图4 图1的子结构示意图 + +### 求子树的代码 + +```c++ +//函数声明,这里是为了先看首先要调用的函数,才放到后面去的。 + bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2); + //正式开始第一个函数 + bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + //因为定义空树不是任何一个树的子树,因此如果有个根节点是空树,那么直接返回false + if(pRoot1 == NULL || pRoot2 == NULL) + return false; + bool result = false; + //如果当前两个树节点值相同,就调用其他函数判断能否以当前节点为根节点下找到相同的子树。 + if(pRoot1->val == pRoot2->val) + { + result = isSubtree(pRoot1, pRoot2); + } + //如果不同或者是以当前节点为根节点下找不到相同的子树,那么就看看A树的左节点或者右节点中有没有。 + if(!result) + result = HasSubtree(pRoot1->left, pRoot2); + if(!result) + result = HasSubtree(pRoot1->right, pRoot2); + return result; + + } + bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + //因为是子树:只要包含了一个结点,就得包含这个结点下的所有节点。 + //因此,A树与其子树一定最后同时访问到空指针。 + if(pRoot2 == NULL && pRoot1 == NULL) + return true; + else if(pRoot2 != NULL && pRoot1 != NULL) + { + if(pRoot1->val != pRoot2->val) + { + return false; + } + return isSubtree(pRoot1->left, pRoot2->left) && isSubtree(pRoot1->right, pRoot2->right); + } + else + return false; + } +``` + +### 求二叉树A子结构的代码 +根据定义,可以知道子树是子结构中的一种特殊情况,因此两段代码之间有很大的相似之处。 +不同之处在于: +1. 子树只要包含了一个结点,就得包含这个结点下的所有节点。因此,A树与其子树一定最后同时访问到空指针。 +2. 子结构只要包含任意相连的任意数量的结点即可。 + +因此,对于子结构而言,只要在子结构访问到空指针之前,所有的节点均和A树的某部分相同就可以了。 + +```c++ +//函数声明,这里是为了先看首先要调用的函数,才放到后面去的。 + bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2); + //正式开始第一个函数 + bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + //因为定义空树不是任何一个树的子树,因此如果有个根节点是空树,那么直接返回false + if(pRoot1 == NULL || pRoot2 == NULL) + return false; + bool result = false; + //如果当前两个树节点值相同,就调用其他函数判断能否以当前节点为根节点下找到相同的子树。 + if(pRoot1->val == pRoot2->val) + { + result = isSubtree(pRoot1, pRoot2); + } + //如果不同或者是以当前节点为根节点下找不到相同的子树,那么就看看A树的左节点或者右节点中有没有。 + if(!result) + result = HasSubtree(pRoot1->left, pRoot2); + if(!result) + result = HasSubtree(pRoot1->right, pRoot2); + return result; + + } + bool isSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + //这里不一样!!!! + //这里不一样!!!! + //这里不一样!!!! + //子结构访问到空指针时,和A树的比较都一直是true就是true. + //而这个函数能一直循环下去,就意味着之前的比较都是true,因此,这里程序改为 + if(pRoot2 == NULL) + return true; + else if(pRoot1 == NULL) + return false; + else if(pRoot2 != NULL && pRoot1 != NULL) + { + if(pRoot1->val != pRoot2->val) + { + return false; + } + return isSubtree(pRoot1->left, pRoot2->left) && isSubtree(pRoot1->right, pRoot2->right); + } + else + return false; + } +``` + + + diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/src/cpp/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.cpp" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/src/cpp/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.cpp" new file mode 100644 index 0000000..2111763 --- /dev/null +++ "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/src/cpp/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.cpp" @@ -0,0 +1,35 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) + { + bool res=false; + if(pRoot1!=nullptr&&pRoot2!=nullptr){ + if(pRoot1->val==pRoot2->val) + res=doesTree1HasTree2(pRoot1,pRoot2); + if(!res) + res=doesTree1HasTree2(pRoot1->left,pRoot2); + if(!res) + res=doesTree1HasTree2(pRoot1->right,pRoot2); + } + return res; + } + + bool doesTree1HasTree2(TreeNode* pRoot1, TreeNode* pRoot2){ + if (pRoot2==nullptr) + return true; + if (pRoot1==nullptr) + return false; + if(pRoot1->val!=pRoot2->val) + return false; + return doesTree1HasTree2(pRoot1->left,pRoot2->left)&&doesTree1HasTree2(pRoot1->right,pRoot2->right); + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/src/python/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.py" "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/src/python/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204/src/python/026-\346\240\221\347\232\204\345\255\220\347\273\223\346\236\204.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/img/readme.assets/basis_18_1.jpg" "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/img/readme.assets/basis_18_1.jpg" new file mode 100644 index 0000000..c525909 Binary files /dev/null and "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/img/readme.assets/basis_18_1.jpg" differ diff --git "a/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/readme.md" "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/readme.md" new file mode 100644 index 0000000..ea4129f --- /dev/null +++ "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/readme.md" @@ -0,0 +1,294 @@ +# 027-二叉树的镜像 + +tags: 二叉树 遍历 递归 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/564f4c26aa584921bc75623e48ca3011?tpId=13&tqId=11171&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +操作给定的二叉[树](https://cuijiahua.com/blog/tag/树/),将其变换为源二叉树的镜像。 + +如下图所示: + +![剑指Offerï¼ˆåå…«ï¼‰ï¼šäºŒå‰æ ‘çš„é•œåƒ](img/readme.assets/basis_18_1.jpg) + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/019-%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%95%9C%E5%83%8F](https://github.com/gatieme/CodingInterviews/tree/master/019-二叉树的镜像)) + +二叉树的镜像结果, 中间像放置了一面镜子,将源二叉树投射在镜子中 + +通常的思路,我们创建一个树以后,交换没个节点的左右孩子就行了。 + +因此我们只需要遍历二叉树,然后每次访问(输出)一个节点的时候。交换其左右孩子即可 + +于是我们实现了下面的递归,非递归的函数版本,其本质是相同的,就是把前序中序,后序遍历中的打印节点的过程,变成交换左右子树的过程,其中需要注意一点,就是交换后左右子树进行了交换,再往下走的时候,往左走往右走的过程需改变,原来的向右走,现在应该是向左走 + +### 递归方法 + +采用递归思路,层层交换节点的左右孩子指针。 + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + void Mirror(TreeNode *pRoot) { + if (pRoot==nullptr) + return; + if(pRoot->left==nullptr&&pRoot->right==nullptr) + return; + TreeNode* temp=pRoot->left; + pRoot->left=pRoot->right; + pRoot->right=temp; + if(pRoot->left!=nullptr) + Mirror(pRoot->left); + if(pRoot->right!=nullptr) + Mirror(pRoot->right); + } +}; +``` + +### 非递归方法 + +#### 前序遍历 + +前序遍历的过程中,先根,再左再右, + +由于根后面才对左右子树进行访问,因此访问顺序可不交换,我们此时的访问顺序依旧是根左右,但是对应原来的根右左 + +```c++ +class Solution +{ +public: + void MirrorPre(TreeNode *root) + { + if(root == NULL) + { + return ; + } + + stack nstack; + TreeNode *node = root; + + while(node != NULL + || nstack.empty( ) != true) + { + while(node != NULL) + { + if(node->left != NULL || node->right != NULL) + { + swap(node->left, node->right); + } + + nstack.push(node); + node = node->left; + } + + if(nstack.empty( ) != true) + { + node = nstack.top( ); + nstack.pop( ); + node = node->right; + } + } + } + + void MirrorPreBFS(TreeNode *root) + { + if(root == NULL) + { + return; + } + stack nstack; + nstack.push(root); + + TreeNode *node = root; + while(nstack.empty() != true) + { + node = nstack.top( ); + nstack.pop( ); + + // 先交换, 然后递归左,接着递归右 + // 相当与一次前序遍历 + if(node->left != NULL || node->right != NULL) + { + swap(node->left, node->right); + } + + if(node->left != NULL) + { + nstack.push(node->left); + } + if(node->right != NULL) + { + nstack.push(node->right); + } + } + } + +}; +``` + +#### 中序遍历 + +中序遍历的时候,访问顺序左根右,由于访问后,依然要向右走, + +所以交换后,变成了向左走 + +```c++ +class Solution +{ +public: + void MirrorIn(TreeNode *root) + { + if(root == NULL) + { + debug <<"The tree is NULL..." < nstack; + TreeNode *node = root; + + // 开始遍历整个二叉树 + while(node != NULL || nstack.empty() != true) + { + // 不输出当前根节点,但是递归直至当前根节点node的最左端 + while(node != NULL) + { + nstack.push(node); + node = node->left; + } + + // 此时栈顶的元素是当前最左元素 + // 它应该被输出 + if(nstack.empty( ) != true) + { + node = nstack.top( ); + + // 将原来的输出改为交换左右子树即可 + if(node->left != NULL || node->right != NULL) + { + swap(node->left, node->right); + } + + nstack.pop( ); + // 中序遍历输出根后,向右转向 + // 此时由于左右子树交换,因此原来的右子树是其左子树,向左转向 + node = node->left; + } + } + } + +}; +``` + +#### 后序遍历 + +跟先序访问一样,访问了左右才会访问根,访问顺序变了 + +```c++ +class Solution +{ +public: + void MirrorPost(TreeNode *root) + { + + if(root == NULL) + { + debug <<"The tree is NULL..." < nstack; + + TreeNode *cur; //当前结点 + TreeNode *pre = NULL; //前一次访问的结点 + nstack.push(root); + + while(nstack.empty( ) != true) + { + cur = nstack.top( ); + + if((cur->left == NULL && cur->right == NULL) // 左右还是均为NULL, 可以被输出 + || (pre != NULL && ((pre == cur->left /*&& cur->right == NULL*/) || pre == cur->right))) // 左右还是被输出了, 递归返回 + + { + ///cout<val; //如果当前结点没有孩子结点或者孩子节点都已被访问过 + // 将原来的输出改为交换左右子树即可 + if(cur->left != NULL || cur->right != NULL) + { + swap(cur->left, cur->right); + } + + nstack.pop( ); + pre = cur; + } + else + { + // 由于栈是先进后出,因此先如后孩子, 再左孩子可以保证递归返回时先遍历左孩子 + if(cur->right != NULL) + { + nstack.push(cur->right); + } + + if(cur->left != NULL) + { + nstack.push(cur->left); + } + } + } + } + + +}; +``` + + + +## 代码 + +### [c++代码](./src/cpp/027-二叉树的镜像.cpp) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + void Mirror(TreeNode *pRoot) { + if (pRoot==nullptr) + return; + if(pRoot->left==nullptr&&pRoot->right==nullptr) + return; + TreeNode* temp=pRoot->left; + pRoot->left=pRoot->right; + pRoot->right=temp; + if(pRoot->left!=nullptr) + Mirror(pRoot->left); + if(pRoot->right!=nullptr) + Mirror(pRoot->right); + } +}; +``` + +### [python代码](./src/python/027-二叉树的镜像.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/src/cpp/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.cpp" "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/src/cpp/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.cpp" new file mode 100644 index 0000000..cf7af36 --- /dev/null +++ "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/src/cpp/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.cpp" @@ -0,0 +1,25 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + void Mirror(TreeNode *pRoot) { + if (pRoot==nullptr) + return; + if(pRoot->left==nullptr&&pRoot->right==nullptr) + return; + TreeNode* temp=pRoot->left; + pRoot->left=pRoot->right; + pRoot->right=temp; + if(pRoot->left!=nullptr) + Mirror(pRoot->left); + if(pRoot->right!=nullptr) + Mirror(pRoot->right); + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/src/python/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.py" "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/src/python/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217/src/python/027-\344\272\214\345\217\211\346\240\221\347\232\204\351\225\234\345\203\217.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_58_1.png" "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_58_1.png" new file mode 100644 index 0000000..bc6c770 Binary files /dev/null and "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_58_1.png" differ diff --git "a/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/readme.md" "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/readme.md" new file mode 100644 index 0000000..ae455d8 --- /dev/null +++ "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/readme.md" @@ -0,0 +1,72 @@ +# 028-对称的二叉树 + +tags: 二叉树 遍历 + +--- + +## 题目原文 + +[牛客网链接]() + +请实现一个函数,用来判断一颗[二叉树](https://cuijiahua.com/blog/tag/二叉树/)是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 + +## 解题思路 + +[参考](https://cuijiahua.com/blog/2018/01/basis_58.html) + +![剑指Offerï¼ˆäº”åå…«ï¼‰ï¼šå¯¹ç§°çš„äºŒå‰æ ‘](img/readme.assets/basis_58_1.png) + +我们通常有三种不同的二叉树遍历算法,即前序遍历、中序遍历和后序遍历。在这三种遍历算法中,都是先遍历左子结点再遍历右子结点。以前序遍历为例,我们可以定义一个遍历算法,先遍历右子结点再遍历左子结点,暂且称其为前序遍历的对称遍历。 + +遍历第一棵树,前序遍历的遍历序列为{8,6,5,7,6,7,5},其对称遍历的遍历序列为{8,6,5,7,6,7,5}。 + +遍历第二颗树,前序遍历的遍历序列为{8,6,5,7,9,7,5},其对称遍历的遍历序列为{8,9,5,7,6,7,5}。 + +可以看到,使用此方法可以区分前两棵树,第一棵树为对称树,第二颗树不是对称树。但是当使用此方法,你会发现第三颗树的前序遍历和对称前序遍历的遍历序列是一样的。 + +怎么区分第三颗树呢?解决办法就是我们也要考虑NULL指针。此时,前序遍历的遍历序列{7,7,7,NULL,NULL,7,NULL,NULL,7,7,NLL,NULL,NULL}, 序列前三个7对应从根节点开始沿着指向左子节点的指针遍历经过的三个节点, 接下来两个NULL指针对应的是第三层第一个节点的两个子节点, 其他的节点直接分析.其对称遍历的遍历序列为{7,7,NULL,7,NULL,NULL,7,7,NULL,NULL,7,NULL,NULL}。因为两种遍历的序列不同,因此这棵树不是对称树。 + +### 难点 + +这道题比较难想到第三个二叉树的情况以及解决办法 + +## 代码 + +### [c++代码](./src/cpp/028-对称的二叉树.cpp) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +}; +*/ +class Solution { +public: + bool isSymmetrical(TreeNode* pRoot) + { + return isSymmetricalCore(pRoot,pRoot); + } + + bool isSymmetricalCore(TreeNode* pRoot1,TreeNode* pRoot2){ + if(pRoot1==nullptr&&pRoot2==nullptr) + return true; + if(pRoot1==nullptr||pRoot2==nullptr) + return false; + if(pRoot1->val!=pRoot2->val) + return false; + return isSymmetricalCore(pRoot1->left,pRoot2->right)&&isSymmetricalCore(pRoot1->right,pRoot2->left); + } + +}; +``` + +### [python代码](./src/python/028-对称的二叉树.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/src/cpp/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.cpp" "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/src/cpp/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.cpp" new file mode 100644 index 0000000..84fa331 --- /dev/null +++ "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/src/cpp/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.cpp" @@ -0,0 +1,28 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +}; +*/ +class Solution { +public: + bool isSymmetrical(TreeNode* pRoot) + { + return isSymmetricalCore(pRoot,pRoot); + } + + bool isSymmetricalCore(TreeNode* pRoot1,TreeNode* pRoot2){ + if(pRoot1==nullptr&&pRoot2==nullptr) + return true; + if(pRoot1==nullptr||pRoot2==nullptr) + return false; + if(pRoot1->val!=pRoot2->val) + return false; + return isSymmetricalCore(pRoot1->left,pRoot2->right)&&isSymmetricalCore(pRoot1->right,pRoot2->left); + } + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/src/python/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.py" "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/src/python/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221/src/python/028-\345\257\271\347\247\260\347\232\204\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153823289-522341390.png" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153823289-522341390.png" new file mode 100644 index 0000000..c7dc0e3 Binary files /dev/null and "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153823289-522341390.png" differ diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153824388-2135481654.png" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153824388-2135481654.png" new file mode 100644 index 0000000..95033a0 Binary files /dev/null and "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153824388-2135481654.png" differ diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153825500-1956530299.png" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153825500-1956530299.png" new file mode 100644 index 0000000..e6030dc Binary files /dev/null and "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153825500-1956530299.png" differ diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153826627-1772650522.png" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153826627-1772650522.png" new file mode 100644 index 0000000..b3000ba Binary files /dev/null and "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/1307402-20180321153826627-1772650522.png" differ diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/basis_19_1.jpg" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/basis_19_1.jpg" new file mode 100644 index 0000000..ec9863a Binary files /dev/null and "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/img/readme.assets/basis_19_1.jpg" differ diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/readme.md" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/readme.md" new file mode 100644 index 0000000..5fad1a2 --- /dev/null +++ "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/readme.md" @@ -0,0 +1,144 @@ +# 029-顺时针打印矩阵 + +tags: 边界条件 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/9b4c81a02cd34f76be2659fa0d54342a?tpId=13&tqId=11172&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: + +![剑指Offer(十九):顺时针打印矩阵](img/readme.assets/basis_19_1.jpg) + +则依次打印出数组:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10。 + +## 解题思路 + +[参考](https://www.cnblogs.com/wanglei5205/p/8617424.html) + + 把矩阵看成由若干个顺时针方向的圈组成,循环打印矩阵中的每个圈,每次循环打印一个圈。打印一圈通常分为四步,第一步从左到右打印一行;第二步从上到下打印一列;第三步从右到左打印一行;第四步从下到上打印一列。设置四个变量left,right,top,btm,用于表示圈的方位,每一步根据起始坐标和终止坐标循环打印。 + +**注意**:最后一圈有可能不需要四步,有可能只有一行,只有一列,只有一个数字,因此我们要仔细分析打印每一步的前提条件: + +- 打印第一步,第一步总是需要的 + + ![image_thumb[19]](img/readme.assets/1307402-20180321153823289-522341390.png) + +- 打印第二步的前提条件是(top2*2.对于一个6*6的矩阵而言,最后一圈有4个数字,其左上角的坐标仍然为(2,2)。我们发现6>2*2依然成立。于是我们可以得出继续循环的条件是columns>startX*2并且rows>startY*2. + + + +## 代码 + +### [c++代码](./src/cpp/029-顺时针打印矩阵.cpp) + +```c++ +class Solution { +public: + vector printMatrix(vector > matrix) { + vector res; + if(matrix.empty()||matrix[0].empty()) + return res; + int rowLength=matrix.size(), colLength=matrix[0].size(); + int startRow=0, startCol=0; + int endRow=rowLength-startRow-1,endCol=colLength-startCol-1; + while(rowLength>startRow*2&&colLength>startCol*2){ + for(int i=startCol;i<=endCol;i++){ + res.push_back(matrix[startRow][i]); + } + if(endRow>startRow){ + for(int i=startRow+1;i<=endRow;i++) + res.push_back(matrix[i][endCol]); + } + if(endRow>startRow&&endCol>startCol){ + for(int i=endCol-1;i>=startCol;i--) + res.push_back(matrix[endRow][i]); + } + + if(endRow-startRow>=2&&endCol>startCol){ + for(int i=endRow-1;i>=startRow+1;i--) + res.push_back(matrix[i][startCol]); + } + startRow++; + startCol++; + endRow--; + endCol--; + } + return res; + } +}; +``` + +### [python代码](./src/python/029-顺时针打印矩阵.py) + +```python + +``` + +## 用一个循环 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/020-%E9%A1%BA%E6%97%B6%E9%92%88%E6%89%93%E5%8D%B0%E7%9F%A9%E9%98%B5](https://github.com/gatieme/CodingInterviews/tree/master/020-顺时针打印矩阵)) + +上面的解法用了两个循环嵌套, 也可以利用一层循环来实现 当然由于也是需要转向,那么我们可以用一个数组来 + +``` +const int D[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; 表示转向操作 +``` + +这样我们的代码成为 + +``` +class Solution +{ + int n, m; + vector > v; + bool judge(int i, int j) + { + return 0 <= i && i < n && 0 <= j && j < m && !v[i][j]; + } + +public: + vector printMatrix(vector > a) + { + vector r; + if((n = a.size()) == 0 || (m = a[0].size()) == 0) + return r; + + v = vector >(n, vector(m, false)); + const int D[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + + int i = 0, j = 0, d = 0, count = m * n; + while(count--) + { + r.push_back(a[i][j]); + v[i][j] = true; + if(!judge(i + D[d][0], j + D[d][1])) + { + (++d) %= 4; //转弯 + } + i += D[d][0]; + j += D[d][1];//前进 + } + return r; + } +}; +``` + diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/src/cpp/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.cpp" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/src/cpp/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.cpp" new file mode 100644 index 0000000..29c6e34 --- /dev/null +++ "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/src/cpp/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.cpp" @@ -0,0 +1,34 @@ +class Solution { +public: + vector printMatrix(vector > matrix) { + vector res; + if(matrix.empty()||matrix[0].empty()) + return res; + int rowLength=matrix.size(), colLength=matrix[0].size(); + int startRow=0, startCol=0; + int endRow=rowLength-startRow-1,endCol=colLength-startCol-1; + while(rowLength>startRow*2&&colLength>startCol*2){ + for(int i=startCol;i<=endCol;i++){ + res.push_back(matrix[startRow][i]); + } + if(endRow>startRow){ + for(int i=startRow+1;i<=endRow;i++) + res.push_back(matrix[i][endCol]); + } + if(endRow>startRow&&endCol>startCol){ + for(int i=endCol-1;i>=startCol;i--) + res.push_back(matrix[endRow][i]); + } + + if(endRow-startRow>=2&&endCol>startCol){ + for(int i=endRow-1;i>=startRow+1;i--) + res.push_back(matrix[i][startCol]); + } + startRow++; + startCol++; + endRow--; + endCol--; + } + return res; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/src/python/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.py" "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/src/python/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265/src/python/029-\351\241\272\346\227\266\351\222\210\346\211\223\345\215\260\347\237\251\351\230\265.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/img/readme.assets/20180607090555318" "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/img/readme.assets/20180607090555318" new file mode 100644 index 0000000..f81aae5 Binary files /dev/null and "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/img/readme.assets/20180607090555318" differ diff --git "a/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/readme.md" "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/readme.md" new file mode 100644 index 0000000..eb0a5a6 --- /dev/null +++ "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/readme.md" @@ -0,0 +1,62 @@ +# 030-包含min函数的栈 + +tags: 栈 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/4c776177d2c04c2494f2555c9fcc1e49?tpId=13&tqId=11173&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(*1*)。 + +## 解题思路 + +[参考](https://blog.csdn.net/u013132035/article/details/80603691) + +要使时间复杂度是O(1),需要每次压入一个新元素进栈时,将栈里的所有元素排序,让最小的元素位于栈顶。但是这种想法不能保证最后压入栈的元素能够最先出栈,因为这个数据结构已经不是栈了。 + +于是借助于一个辅助的成员变量来存放最小的元素。每次压入一个新元素进栈的时候,如果该元素比当前最小的元素还要小,则更新最小元素,但是如果当前做小的元素被弹出栈了,怎么得到下一个最小元素是一个问题。分析到这里我们发现仅仅添加一个成员变量存放最小元素是不够的,也就是说当最小元素被弹出栈的时候,我们希望能够得到次小的元素。因此在压入最小元素之前,我们要把次小元素保存起来。故可以借助一个辅助栈把每次的最小元素都保存起来。 + +例子佐证: + +![img](img/readme.assets/20180607090555318) + +## 代码 + +### [c++代码](./src/cpp/030-包含min函数的栈.cpp) + +```c++ +class Solution { +public: + void push(int value) { + m_data.push(value); + if(m_min.empty()||value m_data; + stack m_min; + +}; +``` + +### [python代码](./src/python/030-包含min函数的栈.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/src/cpp/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.cpp" "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/src/cpp/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.cpp" new file mode 100644 index 0000000..1b36e70 --- /dev/null +++ "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/src/cpp/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.cpp" @@ -0,0 +1,26 @@ +class Solution { +public: + void push(int value) { + m_data.push(value); + if(m_min.empty()||value m_data; + stack m_min; + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/src/python/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.py" "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/src/python/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210/src/python/030-\345\214\205\345\220\253min\345\207\275\346\225\260\347\232\204\346\240\210.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/img/readme.assets/20180607092412743" "b/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/img/readme.assets/20180607092412743" new file mode 100644 index 0000000..fd633f1 Binary files /dev/null and "b/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/img/readme.assets/20180607092412743" differ diff --git "a/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/img/readme.assets/20180607092727969" "b/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/img/readme.assets/20180607092727969" new file mode 100644 index 0000000..4050ed4 Binary files /dev/null and "b/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/img/readme.assets/20180607092727969" differ diff --git "a/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/readme.md" "b/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/readme.md" new file mode 100644 index 0000000..00391f2 --- /dev/null +++ "b/\345\211\221\346\214\207offer/031-\346\240\210\347\232\204\345\216\213\345\205\245\345\274\271\345\207\272\345\272\217\345\210\227/readme.md" @@ -0,0 +1,74 @@ +# 031-栈的压入弹出序列 + +tags: 栈 + +--- + +## 题目原文 + +[牛客网链接]() + +> 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。 + +假设压入栈的所有数字均不相等。 + +例如序列1,2,3,4,5是某栈的压入顺序, + +序列4,5,3,2,1是该压栈序列对应的一个弹出序列, + +但4,3,5,1,2就不可能是该压栈序列的弹出序列。 + +## 解题思路 + +[参考](https://blog.csdn.net/u013132035/article/details/80604096) + +首先借助一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数字。 + +以4、 5、 3、 2 、1为例分析: + +![img](img/readme.assets/20180607092412743) + +再以4、 5、 3、 2 、1为例分析: + +![img](img/readme.assets/20180607092727969) + +从上面的两个例子可以找到判断一个序列是不是栈的弹出序列的规律:如果下一个弹出的数字刚好是栈顶数字,那么直接弹出。如果下一个弹出的数字不在栈顶,我们把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止。如果所有的数字都压入栈了仍然没有找到下一个弹出的数字,那么该序列就不可能是一个弹出序列。 + +## 代码 + +### [c++代码](./src/cpp/031-栈的压入弹出序列.cpp) + +```c++ +class Solution { +public: + bool IsPopOrder(vector pushV,vector popV) { + if(pushV.empty()||popV.empty()||pushV.size()!=popV.size()) + return false; + stack data; + bool res=false; + int idx1=0,idx2=0; + int length=popV.size(); + while(idx2 pushV,vector popV) { + if(pushV.empty()||popV.empty()||pushV.size()!=popV.size()) + return false; + stack data; + bool res=false; + int idx1=0,idx2=0; + int length=popV.size(); + while(idx2 PrintFromTopToBottom(TreeNode* root) { + vector res; + if(root==nullptr) + return res; + queue nodeQueue; + nodeQueue.push(root); + while(!nodeQueue.empty()){ + TreeNode* node=nodeQueue.front(); + nodeQueue.pop(); + res.push_back(node->val); + if(node->left!=nullptr) + nodeQueue.push(node->left); + if(node->right!=nullptr) + nodeQueue.push(node->right); + } + return res; + } +}; +``` + +### [python代码](./src/python/032_01-从上往下打印二叉树.py) + +```python + +``` + +## 举一反三 + +![1562158672058](img/readme.assets/1562158672058.png) + +![1562158685979](img/readme.assets/1562158685979.png) \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/cpp/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.cpp" "b/\345\211\221\346\214\207offer/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/cpp/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.cpp" new file mode 100644 index 0000000..46c34e3 --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/cpp/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.cpp" @@ -0,0 +1,29 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + vector PrintFromTopToBottom(TreeNode* root) { + vector res; + if(root==nullptr) + return res; + queue nodeQueue; + nodeQueue.push(root); + while(!nodeQueue.empty()){ + TreeNode* node=nodeQueue.front(); + nodeQueue.pop(); + res.push_back(node->val); + if(node->left!=nullptr) + nodeQueue.push(node->left); + if(node->right!=nullptr) + nodeQueue.push(node->right); + } + return res; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/python/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" "b/\345\211\221\346\214\207offer/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/python/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/python/032_01-\344\273\216\344\270\212\345\276\200\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160030348.png" "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160030348.png" new file mode 100644 index 0000000..b553720 Binary files /dev/null and "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160030348.png" differ diff --git "a/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160041242.png" "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160041242.png" new file mode 100644 index 0000000..6ce80ea Binary files /dev/null and "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160041242.png" differ diff --git "a/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160051709.png" "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160051709.png" new file mode 100644 index 0000000..51ee8da Binary files /dev/null and "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/img/readme.assets/1562160051709.png" differ diff --git "a/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/readme.md" "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/readme.md" new file mode 100644 index 0000000..5f9098b --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/readme.md" @@ -0,0 +1,81 @@ +# 032_02-把二叉树打印成多行 + +tags: 层次遍历 二叉树 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/445c44d982d04483b04a54f298796288?tpId=13&tqId=11213&tPage=3&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +从上到下按层打印二叉树, 同一层的节点按从左到右的顺序打印, 每一层打印到一行, 例如, 下图中二叉树的打印结果为 + +![1562160030348](img/readme.assets/1562160030348.png) + +## 解题思路 + +![1562160041242](img/readme.assets/1562160041242.png) + +![1562160051709](img/readme.assets/1562160051709.png) + +## 代码 + +### [c++代码](./src/cpp/032_02-把二叉树打印成多行.cpp) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +}; +*/ +class Solution { +public: + vector > Print(TreeNode* pRoot) { + vector> res; + if(pRoot==nullptr) + return res; + int currentLevelNum=1; + int nextLevelNum=0; + queue nodeQueue; + nodeQueue.push(pRoot); + vector level; + while(!nodeQueue.empty()){ + TreeNode* node=nodeQueue.front(); + nodeQueue.pop(); + currentLevelNum--; + level.push_back(node->val); + + if(node->left!=nullptr){ + nodeQueue.push(node->left); + nextLevelNum++; + } + + if(node->right!=nullptr){ + nodeQueue.push(node->right); + nextLevelNum++; + } + + if(currentLevelNum==0){ + res.push_back(level); + vector().swap(level); + currentLevelNum=nextLevelNum; + nextLevelNum=0; + } + } + + return res; + } + +}; +``` + +### [python代码](./src/python/032_02-把二叉树打印成多行.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/src/cpp/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.cpp" "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/src/cpp/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.cpp" new file mode 100644 index 0000000..d323007 --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/src/cpp/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.cpp" @@ -0,0 +1,49 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +}; +*/ +class Solution { +public: + vector > Print(TreeNode* pRoot) { + vector> res; + if(pRoot==nullptr) + return res; + int currentLevelNum=1; + int nextLevelNum=0; + queue nodeQueue; + nodeQueue.push(pRoot); + vector level; + while(!nodeQueue.empty()){ + TreeNode* node=nodeQueue.front(); + nodeQueue.pop(); + currentLevelNum--; + level.push_back(node->val); + + if(node->left!=nullptr){ + nodeQueue.push(node->left); + nextLevelNum++; + } + + if(node->right!=nullptr){ + nodeQueue.push(node->right); + nextLevelNum++; + } + + if(currentLevelNum==0){ + res.push_back(level); + vector().swap(level); + currentLevelNum=nextLevelNum; + nextLevelNum=0; + } + } + + return res; + } + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/src/python/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.py" "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/src/python/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214/src/python/032_02-\346\212\212\344\272\214\345\217\211\346\240\221\346\211\223\345\215\260\346\210\220\345\244\232\350\241\214.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_59_1.png" "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_59_1.png" new file mode 100644 index 0000000..c9bd4ce Binary files /dev/null and "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_59_1.png" differ diff --git "a/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_59_2.png" "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_59_2.png" new file mode 100644 index 0000000..2accc85 Binary files /dev/null and "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/img/readme.assets/basis_59_2.png" differ diff --git "a/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/readme.md" "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/readme.md" new file mode 100644 index 0000000..6cbd7f1 --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/readme.md" @@ -0,0 +1,97 @@ +# 032_03-按之字形顺序打印二叉树 + +tags: 层次遍历 二叉树 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/91b69814117f4e8097390d107d2efbe0?tpId=13&tqId=11212&tPage=3&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。 + + + +![剑指Offerï¼ˆäº”åä¹ï¼‰ï¼šæŒ‰ä¹‹å­—é¡ºåºæ‰“å°äºŒå‰æ ‘](img/readme.assets/basis_59_1.png) + +按之字顺序打印上图二叉树,打印顺序为: + +1 + +3 2 + +4 5 6 7 + +15 14 13 12 12 10 9 8 + +## 解题思路 + +[参考](https://cuijiahua.com/blog/2018/01/basis_59.html) + +为了达到这样打印的效果,我们需要使用两个栈。我们在打印某一行结点时,把下一层的子结点保存到相应的栈里。如果当前打印的是奇数层(第一层、第三层等),则先保存左子树结点再保存右子树结点到第一个栈里。如果当前打印的是偶数层(第二层、第四层等),则则先保存右子树结点再保存左子树结点到第二个栈里。 + +![剑指Offerï¼ˆäº”åä¹ï¼‰ï¼šæŒ‰ä¹‹å­—é¡ºåºæ‰“å°äºŒå‰æ ‘](img/readme.assets/basis_59_2.png) + +## 代码 + +### [c++代码](./src/cpp/032_03-按之字形顺序打印二叉树.cpp) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +}; +*/ +class Solution { +public: + vector > Print(TreeNode* pRoot) { + vector> res; + if(pRoot==nullptr) + return res; + vector v; + stack s[2]; + int current=0; + int next=1; + s[current].push(pRoot); + while(!s[0].empty()||!s[1].empty()){ + TreeNode* node=s[current].top(); + v.push_back(node->val); + s[current].pop(); + + if(current==0){ + if(node->left!=nullptr) + s[next].push(node->left); + if(node->right!=nullptr) + s[next].push(node->right); + }else{ + if(node->right!=nullptr) + s[next].push(node->right); + if(node->left!=nullptr) + s[next].push(node->left); + } + + if(s[current].empty()){ + res.push_back(v); + vector ().swap(v); + current=1-current; + next=1-next; + } + } + + return res; + + } + +}; +``` + +### [python代码](./src/python/032_03-按之字形顺序打印二叉树.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/cpp/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.cpp" "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/cpp/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.cpp" new file mode 100644 index 0000000..1ccccbc --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/cpp/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.cpp" @@ -0,0 +1,51 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +}; +*/ +class Solution { +public: + vector > Print(TreeNode* pRoot) { + vector> res; + if(pRoot==nullptr) + return res; + vector v; + stack s[2]; + int current=0; + int next=1; + s[current].push(pRoot); + while(!s[0].empty()||!s[1].empty()){ + TreeNode* node=s[current].top(); + v.push_back(node->val); + s[current].pop(); + + if(current==0){ + if(node->left!=nullptr) + s[next].push(node->left); + if(node->right!=nullptr) + s[next].push(node->right); + }else{ + if(node->right!=nullptr) + s[next].push(node->right); + if(node->left!=nullptr) + s[next].push(node->left); + } + + if(s[current].empty()){ + res.push_back(v); + vector ().swap(v); + current=1-current; + next=1-next; + } + } + + return res; + + } + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/python/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/python/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221/src/python/032_03-\346\214\211\344\271\213\345\255\227\345\275\242\351\241\272\345\272\217\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/033-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/img/readme.assets/tree.jpg" "b/\345\211\221\346\214\207offer/033-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/img/readme.assets/tree.jpg" new file mode 100644 index 0000000..70377c7 Binary files /dev/null and "b/\345\211\221\346\214\207offer/033-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/img/readme.assets/tree.jpg" differ diff --git "a/\345\211\221\346\214\207offer/033-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/readme.md" "b/\345\211\221\346\214\207offer/033-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/readme.md" new file mode 100644 index 0000000..4f31b0f --- /dev/null +++ "b/\345\211\221\346\214\207offer/033-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227/readme.md" @@ -0,0 +1,93 @@ +# 033-二叉搜索树的后序遍历序列 + +tags: 递归 二叉搜索树 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=11176&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/024-%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97](https://github.com/gatieme/CodingInterviews/tree/master/024-二叉搜索树的后序遍历序列)) + +### 二叉搜索树 + +二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: + +1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值; +2. 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值; +3. 左、右子树也分别为二叉排序树; +4. 没有键值相等的节点。 + +注意:左子树上所有结点的值均小于它的根结点的值 + +**对一棵二叉搜索树进行中序遍历(左根右)可得到一个关键字递增有序序列** + +### 二叉搜索树的后序序列(左右根)特征 + +![äºŒå‰æŽ’åºæ ‘](https://github.com/gatieme/CodingInterviews/raw/master/024-%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97/tree.jpg) + +比如我们的这个二叉排序树 + +> 中序序列 2, 5, 9, 12, 15, 16, 17, 18, 19 +> +> 后序序列 2, 9, 5, 16, 17, 15, 19, 18, 12 + +如果按照后序遍历,先左后右最后自己的顺序来遍历树,数组的最后一个元素肯定是自己(父节点),然后剩余的部分分成两个部分,第一部分都比自己小(左子树部分),第二部分都比自己大(右子树部分),因此套用这个关系就可以循环检验出是否是二叉搜索树的后序遍历了 + +根(最后一个节点)前面被划分为小于它(左子树)和大于它(右子树)的两部分 + +BST的后序序列的合法序列是 + +- 对于一个序列S,最后一个元素是x (也就是根) + +如果去掉最后一个元素的序列为T,那么T满足: + +- T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x, +- 且这两段(子树)都是合法的后序序列。 + +完美的递归定义 + +## 代码 + +### [c++代码](./src/cpp/033-二叉搜索树的后序遍历序列.cpp) + +```c++ +class Solution { +public: + bool VerifySquenceOfBST(vector sequence) { + return VerifySquenceOfBST_Core(sequence,0,sequence.size()-1); + } + bool VerifySquenceOfBST_Core(vector sequence,int start,int end){ + if(sequence.empty()||start>end) + return false; + int i=start; + for(;i<=end-1;i++){ + if(sequence[i]>sequence[end]) + break; + } + int j=i; + for(;j<=end-1;j++){ + if(sequence[j]start) + left=VerifySquenceOfBST_Core(sequence,start,i-1); + bool right=true; + if(i sequence) { + return VerifySquenceOfBST_Core(sequence,0,sequence.size()-1); + } + bool VerifySquenceOfBST_Core(vector sequence,int start,int end){ + if(sequence.empty()||start>end) + return false; + int i=start; + for(;i<=end-1;i++){ + if(sequence[i]>sequence[end]) + break; + } + int j=i; + for(;j<=end-1;j++){ + if(sequence[j]start) + left=VerifySquenceOfBST_Core(sequence,start,i-1); + bool right=true; + if(i5-->4 已近到达叶子结点,不满足要求22,因此该路径访问结束,需要访问下一个路径 + +因为在访问节点的过程中,我们并不知道该路径是否满足要求,所以我们每访问一个节点就要记录该结点 + +访问下有一个结点前,要先从结点4退回到结点5,再访问下一个结点7,因为4不在去往7的路径上,所以要在路径中将4删除 + +10-->5-->7 满足要求,保存该路径 + +访问下一个结点,从结点7回到结点5再回到结点10 + +10-->12,满足要求,保存该路径 + + + +整个流程如下图所示: + +![img](img/readme.assets/20170720152606450.png) + +## 代码 + +### [c++代码](./src/cpp/034-二叉树中和为某一值的路径.cpp) + +![1562204252171](img/readme.assets/1562204252171.png) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + vector > FindPath(TreeNode* root,int expectNumber) { + vector> res; + if(root==nullptr) + return res; + vector path; + int currentSum=0; + FindPathCore(root,expectNumber,res,path,currentSum); + return res; + } + + void FindPathCore(TreeNode* root,int expectNumber,vector>& res, vector& path,int currentSum){ + path.push_back(root->val); + currentSum+=root->val; + //如果是叶节点, 并且路径上节点值的和等于输入值,则保存路径 + bool isLeaf=(root->left==nullptr&&root->right==nullptr); + if(currentSum==expectNumber&&isLeaf){ + res.push_back(path); + } + //如果不是叶节点, 则遍历其子节点 + if(root->left!=nullptr){ + FindPathCore(root->left,expectNumber,res,path,currentSum); + } + if(root->right!=nullptr){ + FindPathCore(root->right,expectNumber,res,path,currentSum); + } + // path需要pop_back而currentSum不需要减去root->val的原因是, 前者是传引用, 后者是传值 + path.pop_back(); + } +}; +``` + +### [python代码](./src/python/034-二叉树中和为某一值的路径.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/src/cpp/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.cpp" "b/\345\211\221\346\214\207offer/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/src/cpp/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.cpp" new file mode 100644 index 0000000..b7fb201 --- /dev/null +++ "b/\345\211\221\346\214\207offer/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/src/cpp/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.cpp" @@ -0,0 +1,40 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + vector > FindPath(TreeNode* root,int expectNumber) { + vector> res; + if(root==nullptr) + return res; + vector path; + int currentSum=0; + FindPathCore(root,expectNumber,res,path,currentSum); + return res; + } + + void FindPathCore(TreeNode* root,int expectNumber,vector>& res, vector& path,int currentSum){ + path.push_back(root->val); + currentSum+=root->val; + //如果是叶节点, 并且路径上节点值的和等于输入值,则保存路径 + bool isLeaf=(root->left==nullptr&&root->right==nullptr); + if(currentSum==expectNumber&&isLeaf){ + res.push_back(path); + } + //如果不是叶节点, 则遍历其子节点 + if(root->left!=nullptr){ + FindPathCore(root->left,expectNumber,res,path,currentSum); + } + if(root->right!=nullptr){ + FindPathCore(root->right,expectNumber,res,path,currentSum); + } + // path需要pop_back而currentSum不需要减去root->val的原因是, 前者是传引用, 后者是传值 + path.pop_back(); + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/src/python/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.py" "b/\345\211\221\346\214\207offer/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/src/python/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204/src/python/034-\344\272\214\345\217\211\346\240\221\344\270\255\345\222\214\344\270\272\346\237\220\344\270\200\345\200\274\347\232\204\350\267\257\345\276\204.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/1.jpg" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/1.jpg" new file mode 100644 index 0000000..0d7fa86 Binary files /dev/null and "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/1.jpg" differ diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/2.jpg" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/2.jpg" new file mode 100644 index 0000000..3f6afe2 Binary files /dev/null and "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/2.jpg" differ diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/3.jpg" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/3.jpg" new file mode 100644 index 0000000..3f6afe2 Binary files /dev/null and "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/3.jpg" differ diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/4-1562207756492.jpg" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/4-1562207756492.jpg" new file mode 100644 index 0000000..8c907dd Binary files /dev/null and "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/4-1562207756492.jpg" differ diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/4.jpg" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/4.jpg" new file mode 100644 index 0000000..8c907dd Binary files /dev/null and "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/img/readme.assets/4.jpg" differ diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/readme.md" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/readme.md" new file mode 100644 index 0000000..ccfbfc9 --- /dev/null +++ "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/readme.md" @@ -0,0 +1,280 @@ +# 035-复杂链表的复制 + +tags: 链表 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?tpId=13&tqId=11178&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +> 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。 +> +> 要求你编写函数复制这个复杂链表 + +复杂链表如下图所示 + +[![复杂链表](img/readme.assets/1.jpg)](https://github.com/gatieme/CodingInterviews/blob/master/026-复杂链表的复制/1.jpg) 复制完后的复杂链表如下图所示 + +[![复杂链表的复制](img/readme.assets/4.jpg)](https://github.com/gatieme/CodingInterviews/blob/master/026-复杂链表的复制/4.jpg) + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/026-%E5%A4%8D%E6%9D%82%E9%93%BE%E8%A1%A8%E7%9A%84%E5%A4%8D%E5%88%B6](https://github.com/gatieme/CodingInterviews/tree/master/026-复杂链表的复制)) + +### 暴力方法 + +最简单暴力的方法: + +很明显,链表分成两个部分,一个是下一个节点组成的链表,另一个特殊指针的链接。 + +那么我们的复制操作可以分成两个部分 + +- 复制正常的链表指针域 这个操作比较简单,因为链表的下一个指针为形成一个串的,我们从头开始即可遍历所有的结点 +- 复制随机的指针域 这个操作有点麻烦,由于指针是随机指向的,因此无法通过一趟遍历来实现,这里我们采用暴力的方式, 由于指针的位置是一一对应的,我们查找到原来的随机指针域在新链表中对应位置($O(N)$),而我们遍历一遍将所有的随机指针都复制则需要$O(N^2)$ + +代码如下 + +```c++ +class Solution +{ +public: + /// 找到newHead指向的新链表中与原来链表oldHead的randNode节点对应的那个节点 + /// + /// 复制的链表newHead与原链表oldHead存在一一对应的关系 + /// 因此使用两个指针(一个指向原来链表一个指向新链表)同步移动 + /// 即可找到newHead指向的新链表中与原来链表oldHead的randNode节点对应的那个节点 + RandomListNode* FindInNew(RandomListNode *oldHead, RandomListNode *newHead, RandomListNode *randNode) + { + RandomListNode *currNode = oldHead; + RandomListNode *newNode = newHead; + + while(currNode != NULL && newNode != NULL) + { + if(randNode == currNode) + { + return newNode; + } + currNode = currNode->next; + newNode = newNode->next; + } + + return NULL; + } + + /// 复制操作 + RandomListNode* Clone(RandomListNode* pHead) + { + if(pHead == NULL) + { + return NULL; + } + + RandomListNode *currNode = pHead; + RandomListNode *newHead = NULL, *preNode = NULL, *newNode = NULL; + + /// 首先复制原链表的普通指针域, 一次遍历即可完成 + while(currNode != NULL) + { + newNode = new RandomListNode(currNode->label); + currNode = currNode->next; + + if(preNode == NULL) + { + newHead = newNode; + } + else + { + preNode->next = newNode; + } + + preNode = newNode; + } + + // 接着复制随机指针域, 需要两次遍历 + currNode = pHead; + newNode = newHead; + while(currNode != NULL && newNode != NULL) + { + RandomListNode *randNode = currNode->random; /// 随机指针域randNode + RandomListNode *newRandNode = FindInNew(pHead, newHead, randNode); /// 查找到新链表中与randNode对应的指针域 + newNode->random = newRandNode; + + /// 链表同步移动 + currNode = currNode->next; + newNode = newNode->next; + } + + return newHead; + } + +}; +``` + +### 用map来存储新旧链表的节点对应关系(空间换取时间() + +> 其实分析一下子就知道我们的暴力解法的性能缺陷在哪? + +我们每次复制随机指针的时候,找到newHead指向的新链表中与原来链表oldHead的randNode节点对应的那个节点时,需要同步遍历两个链表,这个过程是$O(n)$的 + +> 有没有什么方法把这个动作的时间复杂度降低到$O(1)$呢? + +由于新旧链表中的节点是一一对应的,那么我们用空间换时间的方法,用一个map或者hashtable来存储这个映射关系 + +```c++ +class Solution +{ +public: + + /// 复制操作 + RandomListNode* Clone(RandomListNode* pHead) + { + if(pHead == NULL) + { + return NULL; + } + map nodeMap; + + RandomListNode *currNode = pHead; + RandomListNode *newHead = NULL, *preNode = NULL, *newNode = NULL; + + /// 首先复制原链表的普通指针域, 一次遍历即可完成 + while(currNode != NULL) + { + newNode = new RandomListNode(currNode->label); + nodeMap[currNode] = newNode; + currNode = currNode->next; + + if(preNode == NULL) + { + newHead = newNode; + } + else + { + preNode->next = newNode; + } + + preNode = newNode; + } + + // 接着复制随机指针域, 需要两次遍历 + currNode = pHead; + newNode = newHead; + while(currNode != NULL && newNode != NULL) + { + RandomListNode *randNode = currNode->random; /// 随机指针域randNode + RandomListNode *newRandNode = nodeMap[randNode]; + newNode->random = newRandNode; + + /// 链表同步移动 + currNode = currNode->next; + newNode = newNode->next; + } + + return newHead; + } + +}; +``` + +### 用next指针域关联新旧结点 + +上面那种方法,我们用map来存储新旧链表中结点的对应关系,对于右N个节点的链表,我么就用了一个大小为$O(N)$的map的空间消耗将时间复杂度从$O(N^2)$降到了$O(N)$ 那么有没有什么方法,能够将空间复杂度也降下来,在使用不用辅助空间的情况下实现$O(N)$的时间效率 + +其实我们需要的就只是能够建立新节点与原节点之前的对应关系就可以了, 链表中的顺序非随机访问方式,能够很简单的通过接单的nex指针t域查找下一个节点,那么我们将新节点直接插入到原结点的后面,这样可以很方便的通过原来节点找到新节点, + +因此我们算法的流程如下: + +1. 遍历一遍原始链表,复制结点N对应的N',将其插入到结点N的后面,如下图所示 + +[![链接](img/readme.assets/2.jpg)](https://github.com/gatieme/CodingInterviews/blob/master/026-复杂链表的复制/2.jpg) + +1. 确定每个随机指针的指向,只需遍历一遍链表即可确定每个结点的随机指针的指向,得到如下图结构 + +[![链接](img/readme.assets/3.jpg)](https://github.com/gatieme/CodingInterviews/blob/master/026-复杂链表的复制/3.jpg) + +1. 再次遍历一遍,将原始链表和复制链表分开,奇数为原始链表,偶数为复制链表,得到如下图型 + +[![链接](img/readme.assets/4-1562207756492.jpg)](https://github.com/gatieme/CodingInterviews/blob/master/026-复杂链表的复制/4.jpg) + +``` +class Solution +``` + +## 代码 + +### [c++代码](./src/cpp/035-复杂链表的复制.cpp) + +```c++ +/* +struct RandomListNode { + int label; + struct RandomListNode *next, *random; + RandomListNode(int x) : + label(x), next(NULL), random(NULL) { + } +}; +*/ +class Solution { +public: + RandomListNode* Clone(RandomListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + CloneNodes(pHead); + ConnectRandomNodes(pHead); + return ReconnectNodes(pHead); + } + + void CloneNodes(RandomListNode* pHead){ + RandomListNode* node=pHead; + + while(node!=nullptr){ + RandomListNode* cloneNode=new RandomListNode(0); + cloneNode->label=node->label; + cloneNode->next=node->next; + cloneNode->random=nullptr; + node->next=cloneNode; + node=cloneNode->next; + } + } + + void ConnectRandomNodes(RandomListNode* pHead){ + RandomListNode* node=pHead; + RandomListNode* cloneNode=node->next; + + while(node!=nullptr){ + if(node->random!=nullptr){ + cloneNode->random=node->random->next; + } + node=cloneNode->next; + cloneNode=node->next; + } + } + + RandomListNode* ReconnectNodes(RandomListNode* pHead){ + RandomListNode* node=pHead; + RandomListNode* cloneHead=nullptr; + RandomListNode* cloneNode=nullptr; + + cloneNode=cloneHead=node->next; + node->next=cloneNode->next; + node=cloneNode->next; + + while(node!=nullptr){ + cloneNode->next=node->next; + cloneNode=node->next; + node->next=cloneNode->next; + node=node->next; + } + + return cloneHead; + } +}; +``` + +### [python代码](./src/python/035-复杂链表的复制.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/src/cpp/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.cpp" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/src/cpp/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.cpp" new file mode 100644 index 0000000..36e94dd --- /dev/null +++ "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/src/cpp/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.cpp" @@ -0,0 +1,65 @@ +/* +struct RandomListNode { + int label; + struct RandomListNode *next, *random; + RandomListNode(int x) : + label(x), next(NULL), random(NULL) { + } +}; +*/ +class Solution { +public: + RandomListNode* Clone(RandomListNode* pHead) + { + if(pHead==nullptr) + return nullptr; + CloneNodes(pHead); + ConnectRandomNodes(pHead); + return ReconnectNodes(pHead); + } + + void CloneNodes(RandomListNode* pHead){ + RandomListNode* node=pHead; + + while(node!=nullptr){ + RandomListNode* cloneNode=new RandomListNode(0); + cloneNode->label=node->label; + cloneNode->next=node->next; + cloneNode->random=nullptr; + node->next=cloneNode; + node=cloneNode->next; + } + } + + void ConnectRandomNodes(RandomListNode* pHead){ + RandomListNode* node=pHead; + RandomListNode* cloneNode=node->next; + + while(node!=nullptr){ + if(node->random!=nullptr){ + cloneNode->random=node->random->next; + } + node=cloneNode->next; + cloneNode=node->next; + } + } + + RandomListNode* ReconnectNodes(RandomListNode* pHead){ + RandomListNode* node=pHead; + RandomListNode* cloneHead=nullptr; + RandomListNode* cloneNode=nullptr; + + cloneNode=cloneHead=node->next; + node->next=cloneNode->next; + node=cloneNode->next; + + while(node!=nullptr){ + cloneNode->next=node->next; + cloneNode=node->next; + node->next=cloneNode->next; + node=node->next; + } + + return cloneHead; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/src/python/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.py" "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/src/python/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266/src/python/035-\345\244\215\346\235\202\351\223\276\350\241\250\347\232\204\345\244\215\345\210\266.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/img/readme.assets/basis_26_1.jpg" "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/img/readme.assets/basis_26_1.jpg" new file mode 100644 index 0000000..54671d4 Binary files /dev/null and "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/img/readme.assets/basis_26_1.jpg" differ diff --git "a/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/readme.md" "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/readme.md" new file mode 100644 index 0000000..5f538b1 --- /dev/null +++ "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/readme.md" @@ -0,0 +1,83 @@ +# 036-二叉搜索树与双向链表 + +tags: 二叉搜索树 中序遍历 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&tqId=11179&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的[双向链表](https://cuijiahua.com/blog/tag/双向链表/)。要求不能创建任何新的结点,只能调整树中结点指针的指向。 + +## 解题思路 + +[参考](https://cuijiahua.com/blog/2017/12/basis_26.html) + +![剑指Offerï¼ˆäºŒåå…­ï¼‰ï¼šäºŒå‰æœç´¢æ ‘ä¸ŽåŒå‘é“¾è¡¨](img/readme.assets/basis_26_1.jpg) + +二叉搜索树如上图所示,我们将其转换为配需[双向链表](https://cuijiahua.com/blog/tag/双向链表/)。 + +根据二叉搜索树的特点:左结点的值<根结点的值<右结点的值,我们不难发现,使用[二叉树](https://cuijiahua.com/blog/tag/二叉树/)的中序遍历出来的数据的数序,就是排序的顺序。因此,首先,确定了二叉搜索树的遍历方法。 + +接下来,我们看下图,我们可以把树分成三个部分:值为10的结点、根结点为6的左子树、根结点为14的右子树。根据排序双向链表的定义,值为10的结点将和它的左子树的最大一个结点链接起来,同时它还将和右子树最小的结点链接起来。 + +按照中序遍历的顺序,当我们遍历到根结点时,它的左子树已经转换成一个排序的好的双向链表了,并且处在链表中最后一个的结点是当前值最大的结点。我们把值为8的结点和根结点链接起来,10就成了最后一个结点,接着我们就去遍历右子树,并把根结点和右子树中最小的结点链接起来。至于如何把左子树和右子树的内部节点链接为链表, 那和原来问题是一样的, 可以用递归解决. + +在我们的递归函数中,我们用pLastNodeInList保存前一个访问的节点,我们采用中序访问的方式,将访问当前结点currNode的操作转换为将当前节点currNode与前一个节点pLastNodeInList链接成链表的方式。 + +由于我们每次需要更新pLastNodeInList的值,所以我们传递的参数是指向pLastNodeInList的指针 + +## 代码 + +### [c++代码](./src/cpp/036-二叉搜索树与双向链表.cpp) + +```c++ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + TreeNode* Convert(TreeNode* pRootOfTree) + { + if(pRootOfTree==nullptr) + return nullptr; + TreeNode* pLastNodeInList=nullptr; + ConvertCore(pRootOfTree,&pLastNodeInList); + while(pLastNodeInList!=nullptr&&pLastNodeInList->left!=nullptr) + pLastNodeInList=pLastNodeInList->left; + return pLastNodeInList; + } + void ConvertCore(TreeNode* pRootOfTree,TreeNode** pLastNodeInList){ + if(pRootOfTree==nullptr) + return; + TreeNode* currentNode=pRootOfTree; + + if(currentNode->left!=nullptr) + ConvertCore(currentNode->left,pLastNodeInList); + + currentNode->left=*pLastNodeInList; + + if(*pLastNodeInList!=nullptr) + (*pLastNodeInList)->right=currentNode; + + currentNode->left=*pLastNodeInList; + *pLastNodeInList=currentNode; + + if(currentNode->right!=nullptr) + ConvertCore(currentNode->right,pLastNodeInList); + } +}; +``` + +### [python代码](./src/python/036-二叉搜索树与双向链表.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/src/cpp/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.cpp" "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/src/cpp/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.cpp" new file mode 100644 index 0000000..d7f51e1 --- /dev/null +++ "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/src/cpp/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.cpp" @@ -0,0 +1,41 @@ +/* +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; + TreeNode(int x) : + val(x), left(NULL), right(NULL) { + } +};*/ +class Solution { +public: + TreeNode* Convert(TreeNode* pRootOfTree) + { + if(pRootOfTree==nullptr) + return nullptr; + TreeNode* pLastNodeInList=nullptr; + ConvertCore(pRootOfTree,&pLastNodeInList); + while(pLastNodeInList!=nullptr&&pLastNodeInList->left!=nullptr) + pLastNodeInList=pLastNodeInList->left; + return pLastNodeInList; + } + void ConvertCore(TreeNode* pRootOfTree,TreeNode** pLastNodeInList){ + if(pRootOfTree==nullptr) + return; + TreeNode* currentNode=pRootOfTree; + + if(currentNode->left!=nullptr) + ConvertCore(currentNode->left,pLastNodeInList); + + currentNode->left=*pLastNodeInList; + + if(*pLastNodeInList!=nullptr) + (*pLastNodeInList)->right=currentNode; + + currentNode->left=*pLastNodeInList; + *pLastNodeInList=currentNode; + + if(currentNode->right!=nullptr) + ConvertCore(currentNode->right,pLastNodeInList); + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/src/python/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.py" "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/src/python/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250/src/python/036-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\216\345\217\214\345\220\221\351\223\276\350\241\250.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/readme.md" "b/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/readme.md" new file mode 100644 index 0000000..6a411ec --- /dev/null +++ "b/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/readme.md" @@ -0,0 +1,109 @@ +# 037-序列化二叉树 + +tags: 二叉树 前序遍历 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=13&tqId=11214&tPage=4&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +请实现两个函数,分别用来序列化和反序列化二叉树 + +## 解题思路 + +其实这道题约定的序列化没有固定的格式, 只要你序列化后的结果, 再反序列化后与原树相同即可, + +因此我们可以随意指定自己的格式, + +比如空节点用$表示,或则#表示, + +然后遍历采用先序, 中序, 后序或者层次都可以, + +我们的示例程序中采用空结点用#表示, 结点与结点用逗号,分隔 + +选择了合适的遍历算法, 那么剩下的问题就是字符串序列和整数权值的相互转换问题 + +- 序列化的关键, 其实就是将树的权值(整数)转换为字符串序列, 可以采用ostringstream, sprintf和itoa +- 反序列化的关键, 则正好相反, 将字符串转换为整数, 可以使用istringstream, sscanf和atoi + +这道题比较麻烦的是序列化的结果与int和char的转换 + +## 代码 + +### [c++代码](./src/cpp/037-序列化二叉树.cpp) + +```c++ +/* +struct TreeNode { +int val; +struct TreeNode *left; +struct TreeNode *right; +TreeNode(int x) : +val(x), left(NULL), right(NULL) { +} +}; +*/ +class Solution { +public: + char* Serialize(TreeNode *root) { + if (root == nullptr) + return nullptr; + string str; + SerializeCore(root, str); + char* res = new char[str.length() + 1]; + const char* c_str = str.c_str(); + strcpy(res, c_str); + return res; + } + TreeNode* Deserialize(char *str) { + if (!str) { + return NULL; + } + TreeNode* res = DeserializeCore(&str); + return res; + } + + void SerializeCore(TreeNode *root, string& str) { + if (root == nullptr) { + str += '#'; + return; + } + string temp = to_string(root->val); + str += temp; + str += ','; + SerializeCore(root->left, str); + SerializeCore(root->right, str); + } + // 递归时改变了str值使其指向后面的序列,因此要声明为char** + TreeNode* DeserializeCore(char** str) { + // 到达叶节点时,调用两次,都返回null,所以构建完毕,返回父节点的构建 + if (**str == '#') { + (*str)++; + return NULL; + } + // 因为整数是用字符串表示,一个字符表示一位,先进行转换 + int num = 0; + while (**str != ',' && **str != '\0') { + num = num * 10 + ((**str) - '0'); + (*str)++; + } + TreeNode* root = new TreeNode(num); + if (**str == '\0') { + return root; + } + else { + (*str)++; + } + root->left = DeserializeCore(str); + root->right = DeserializeCore(str); + return root; + } +}; +``` + +### [python代码](./src/python/037-序列化二叉树.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/src/cpp/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.cpp" "b/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/src/cpp/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.cpp" new file mode 100644 index 0000000..37a286d --- /dev/null +++ "b/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/src/cpp/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.cpp" @@ -0,0 +1,66 @@ +/* +struct TreeNode { +int val; +struct TreeNode *left; +struct TreeNode *right; +TreeNode(int x) : +val(x), left(NULL), right(NULL) { +} +}; +*/ +class Solution { +public: + char* Serialize(TreeNode *root) { + if (root == nullptr) + return nullptr; + string str; + SerializeCore(root, str); + char* res = new char[str.length() + 1]; + const char* c_str = str.c_str(); + strcpy(res, c_str); + return res; + } + TreeNode* Deserialize(char *str) { + if (!str) { + return NULL; + } + TreeNode* res = DeserializeCore(&str); + return res; + } + + void SerializeCore(TreeNode *root, string& str) { + if (root == nullptr) { + str += '#'; + return; + } + string temp = to_string(root->val); + str += temp; + str += ','; + SerializeCore(root->left, str); + SerializeCore(root->right, str); + } + // 递归时改变了str值使其指向后面的序列,因此要声明为char** + TreeNode* DeserializeCore(char** str) { + // 到达叶节点时,调用两次,都返回null,所以构建完毕,返回父节点的构建 + if (**str == '#') { + (*str)++; + return NULL; + } + // 因为整数是用字符串表示,一个字符表示一位,先进行转换 + int num = 0; + while (**str != ',' && **str != '\0') { + num = num * 10 + ((**str) - '0'); + (*str)++; + } + TreeNode* root = new TreeNode(num); + if (**str == '\0') { + return root; + } + else { + (*str)++; + } + root->left = DeserializeCore(str); + root->right = DeserializeCore(str); + return root; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/src/python/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.py" "b/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/src/python/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221/src/python/037-\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\240\221.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/img/readme.assets/7578108_1499250116235_8F032F665EBB2978C26C4051D5B89E90.png" "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/img/readme.assets/7578108_1499250116235_8F032F665EBB2978C26C4051D5B89E90.png" new file mode 100644 index 0000000..f2f6390 Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/img/readme.assets/7578108_1499250116235_8F032F665EBB2978C26C4051D5B89E90.png" differ diff --git "a/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/img/readme.assets/basis_27_1.jpg" "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/img/readme.assets/basis_27_1.jpg" new file mode 100644 index 0000000..cb5a72c Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/img/readme.assets/basis_27_1.jpg" differ diff --git "a/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/readme.md" "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/readme.md" new file mode 100644 index 0000000..c884fcd --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/readme.md" @@ -0,0 +1,165 @@ +# 038_01-字符串的排列 + +tags: 全排列 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&tqId=11180&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 + +牛客网的要求应该是只需要去重复, 不需要考虑按字母顺序输出. + +## 解题思路 + +### 不考虑去重复和字母顺序输出 + +我们求整个字符串的排列,可以看成两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。如下图所示: + +[![剑指Offer(二十七):字符串的排列](img/readme.assets/basis_27_1.jpg)](https://cuijiahua.com/wp-content/uploads/2017/12/basis_27_1.jpg) + +上图就是分别把第一个字符a和后面的b、c等字符交换的情形。首先固定第一个字符,求后面所有字符的排列。这个时候我们仍把后面的所有字符分为两部分:后面的字符的第一个字符,以及这个字符之后的所有字符。然后把第一个字符逐一和它后面的字符交换。 + +这个思路,是典型的递归思路。 + +![图片说明](img/readme.assets/7578108_1499250116235_8F032F665EBB2978C26C4051D5B89E90.png) + +```c++ +class Solution { +public: + vector Permutation(string str) { + //判断输入 + if(str.length() == 0){ + return result; + } + PermutationCore(str, 0); + return result; + } + +private: + void PermutationCore(string str, int begin){ + //递归结束的条件:第一位和最后一位交换完成 + if(begin == str.length()){ + result.push_back(str); + return; + } + for(int i = begin; i < str.length(); i++){ + //位置交换 + swap(str[begin], str[i]); + //递归调用,前面begin+1的位置不变,后面的字符串全排列 + PermutationCore(str, begin + 1); + } + } + vector result; +}; +``` + +### 考虑去重复 + +对于形如 **aba** 或 **aa** 等特殊测试用例的情况 + +可在for循环中添加 + +```c++ + for(int i = begin; i < str.length(); i++){ + //如果字符串相同,则不交换 + if(i != begin && str[i] == str[begin]){ + continue; + } + //位置交换 + swap(str[begin], str[i]); + //递归调用,前面begin+1的位置不变,后面的字符串全排列 + PermutationCore(str, begin + 1); + } +``` + +### 考虑字母顺序输出 + +```c++ +sort(result.begin(), result.end()); +``` + +### STL的next_permutation求全排列 + +用STL的next_permutation可以很方便的求一个容器的全排列 + +[next_permutation](https://www.cnblogs.com/eudiwffe/p/6260699.html) + +[prev_permutation](http://c.biancheng.net/view/598.html) + +```c++ +class Solution +{ +public: + vector Permutation(string str) + { + vector res; + + if(str.empty( ) == true) + { + return res; + } + sort(str.begin( ), str.end( )); + + do + { + res.push_back(str); + } + while(next_permutation(str.begin( ), str.end( ))); + + + return res; + + } +}; +``` + + + +## 代码 + +### [c++代码](./src/cpp/038_01-字符串的排列.cpp) + +```c++ +class Solution { +public: + vector Permutation(string str) { + //判断输入 + if(str.length() == 0){ + return result; + } + PermutationCore(str, 0); + //对结果进行排序 + sort(result.begin(), result.end()); + return result; + } + +private: + void PermutationCore(string str, int begin){ + //递归结束的条件:第一位和最后一位交换完成 + if(begin == str.length()){ + result.push_back(str); + return; + } + for(int i = begin; i < str.length(); i++){ + //如果字符串相同,则不交换 + if(i != begin && str[i] == str[begin]){ + continue; + } + //位置交换 + swap(str[begin], str[i]);//str是传值形参, 所以递归返回后不会改变str + //递归调用,前面begin+1的位置不变,后面的字符串全排列 + PermutationCore(str, begin + 1); + } + } + vector result; +}; +``` + +### [python代码](./src/python/038_01-字符串的排列.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/src/cpp/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.cpp" "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/src/cpp/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.cpp" new file mode 100644 index 0000000..ba6aada --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/src/cpp/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.cpp" @@ -0,0 +1,33 @@ +class Solution { +public: + vector Permutation(string str) { + //判断输入 + if(str.length() == 0){ + return result; + } + PermutationCore(str, 0); + //对结果进行排序 + sort(result.begin(), result.end()); + return result; + } + +private: + void PermutationCore(string str, int begin){ + //递归结束的条件:第一位和最后一位交换完成 + if(begin == str.length()){ + result.push_back(str); + return; + } + for(int i = begin; i < str.length(); i++){ + //如果字符串相同,则不交换 + if(i != begin && str[i] == str[begin]){ + continue; + } + //位置交换 + swap(str[begin], str[i]); + //递归调用,前面begin+1的位置不变,后面的字符串全排列 + PermutationCore(str, begin + 1); + } + } + vector result; +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/src/python/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.py" "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/src/python/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227/src/python/038_01-\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/03408dfe78564b721a065bf3bb34bc4e933f321a6e5e5883f0a5096a88dadb0b-\350\247\243\346\236\220.png" "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/03408dfe78564b721a065bf3bb34bc4e933f321a6e5e5883f0a5096a88dadb0b-\350\247\243\346\236\220.png" new file mode 100644 index 0000000..797e98e Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/03408dfe78564b721a065bf3bb34bc4e933f321a6e5e5883f0a5096a88dadb0b-\350\247\243\346\236\220.png" differ diff --git "a/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/6c3e9f5a3397b59b00ded7554c73a06358def4933a473711a1dbdd22b2766ed3-78-1-bit-mask.png" "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/6c3e9f5a3397b59b00ded7554c73a06358def4933a473711a1dbdd22b2766ed3-78-1-bit-mask.png" new file mode 100644 index 0000000..54b4d49 Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/6c3e9f5a3397b59b00ded7554c73a06358def4933a473711a1dbdd22b2766ed3-78-1-bit-mask.png" differ diff --git "a/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/readme.md" "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/readme.md" new file mode 100644 index 0000000..35ffd6f --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/readme.md" @@ -0,0 +1,246 @@ +# 038_02-全组合-不含重复元素 + +tags: 全组合 + +--- + +## 题目原文 + +[leetcode链接](https://leetcode-cn.com/problems/subsets/) + +给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + +**说明:**解集不能包含重复的子集。 + +**示例:** + +``` +输入: nums = [1,2,3] +输出: +[ + [3], + [1], + [2], + [1,2,3], + [1,3], + [2,3], + [1,2], + [] +] +``` + + + +## 解题思路 + +### 剑指offer的方法 + +[参考](https://www.cnblogs.com/zengshangzhi/p/9305534.html) + +假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码: + +```c++ +class Solution { +public: + vector> subsets(vector& nums) { + if(nums.empty()) + return res; + res.push_back(v); + for(int i=1;i<=nums.size();i++){ + subsetsCore(nums,0,i); + } + return res; + } +private: + void subsetsCore(vector& nums,int begin,int m){ + if(m==0){ + res.push_back(v); + return; + } + if(begin==nums.size()){ + return; + } + v.push_back(nums[begin]); + subsetsCore(nums,begin+1,m-1); + v.pop_back(); + subsetsCore(nums,begin+1,m); + + } + vector v; + vector> res; +}; +``` + +### 位运算或者说bitmap + +[参考](https://leetcode-cn.com/problems/subsets/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--10/) + +数组的每个元素,可以有两个状态,在子数组中和不在子数组中,所有状态的组合就是所有子数组了。 + +例如,nums = [ 1, 2 , 3 ]。1 代表在,0 代表不在。 + +1 2 3 +0 0 0 -> [ ] +0 0 1 -> [ 3] +0 1 0 -> [ 2 ] +0 1 1 -> [ 2 3] +1 0 0 -> [1 ] +1 0 1 -> [1 3] +1 1 0 -> [1 2 ] +1 1 1 -> [1 2 3] + +![78-1-bit-mask.png](img/readme.assets/6c3e9f5a3397b59b00ded7554c73a06358def4933a473711a1dbdd22b2766ed3-78-1-bit-mask.png) + +所以我们只需要遍历 0 0 0 到 1 1 1,也就是 0 到 7,然后判断每个比特位是否是 1,是 1 的话将对应数字加入即可。如果数组长度是 n,那么每个比特位是 2 个状态,所有总共就是 2 的 n 次方个子数组。遍历 00 ... 0 到 11 ... 1 即可。 + +或者 + +``` +// 这种写法输出为: [[],[3],[2],[3,2],[1],[3,1],[2,1],[3,2,1]] +// 这种写法位掩码的对应情况为 +/* +000->[] +001->[3] +010->[2] +011->[3,2] +... +*/ + +class Solution { +public: + vector> subsets(vector& nums) { + int n = nums.size(); + int all = 1 << n; + vector> res;//存放最后的结果 + + for(int i = 0; i < all; i++){ + vector vec; + for(int j = 0; j < nums.size(); j++){ + if((i & (1 << j)) != 0){ + vec.push_back(nums[j]); + } + } + res.push_back(vec); + } + return res; + } +}; +``` + + + +```c++ +// 这种写法输出为: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] +// 这种写法位掩码的对应情况为 +/* +000->[] +001->[1] +010->[2] +011->[1,2] +... +相当于把位掩码做水平镜像 +*/ +// 这么写计算量少一些 +class Solution { +public: + vector> subsets(vector& nums) { + int n = nums.size(); + int all = 1 << n; + vector> res;//存放最后的结果 + + for(int i = 0; i < all; i++){ + vector vec; + for(int j = 0; j < nums.size(); j++){ + if((i & (1 << j)) != 0){ + vec.push_back(nums[j]); + } + } + res.push_back(vec); + } + return res; + } +}; +``` + +### 迭代法 + +[参考](https://blog.csdn.net/camellhf/article/details/73551410) + +一个规律,集合中每添加一个元素,则子集数目增加一倍,且增加的子集为所有原始子集加上新的元素。举个例子:nums=[1,2,3] + +1. 初始时集合为空,子集为[ [] ]。 +2. 添加一个元素1,即集合为[1]时,子集为空集和空集+元素1,即[ [], [1] ]。 +3. 添加下一个元素2,集合为[1,2],子集除了包含上一步的所有集合还新增了对应集合+元素2的所有集合,即[ [], [1], [2], [1,2]],其中[2]是空集+元素2,[1,2]是[1]+元素2。 +4. 添加下一个元素3,集合为[1,2,3],类似的得到子集为[ [], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3] ],其中[3]是空集+元素3,[1,3]是[1]+元素3,[2,3]是[2]+元素3,[1,2,3]是[1,2]+元素3。 +因此,利用这个规律构建子集,实现过程见参考代码 + +![解析.png](img/readme.assets/03408dfe78564b721a065bf3bb34bc4e933f321a6e5e5883f0a5096a88dadb0b-解析.png) + +```c++ +class Solution { +public: + vector> subsets(vector& nums) { + vector> res(1, vector()); + + for (int i = 0; i < nums.size(); i++) { + int n = res.size(); + for (int j = 0; j < n; j++) { + res.push_back(res[j]); + res.back().push_back(nums[i]); + } + } + + return res; + } +}; +``` + + + +### 总结 + +[参考](https://blog.csdn.net/camellhf/article/details/73551410) + +这道题蛮简单的,关键是要通过不同的解法开阔自己的思路,做题最重要的不是AC,而是在于通过后进行总结反思。通过学习其他人的代码,我学到了很多小技巧,尽管不可能直接在其他题目上套用,但是会对其他题的思考有所启发。 + +## 代码 + +### [c++代码](./src/cpp/038_02-全组合-不含重复元素.cpp) + +```c++ +class Solution { +public: + vector> subsets(vector& nums) { + if(nums.empty()) + return res; + res.push_back(v); + for(int i=1;i<=nums.size();i++){ + subsetsCore(nums,0,i); + } + return res; + } +private: + void subsetsCore(vector& nums,int begin,int m){ + if(m==0){ + res.push_back(v); + return; + } + if(begin==nums.size()){ + return; + } + v.push_back(nums[begin]); + subsetsCore(nums,begin+1,m-1); + v.pop_back(); + subsetsCore(nums,begin+1,m); + + } + vector v; + vector> res; +}; +``` + +### [python代码](./src/python/038_02-全组合-不含重复元素.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/cpp/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.cpp" "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/cpp/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.cpp" new file mode 100644 index 0000000..d0fadb0 --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/cpp/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.cpp" @@ -0,0 +1,29 @@ +class Solution { +public: + vector> subsets(vector& nums) { + if(nums.empty()) + return res; + res.push_back(v); + for(int i=1;i<=nums.size();i++){ + subsetsCore(nums,0,i); + } + return res; + } +private: + void subsetsCore(vector& nums,int begin,int m){ + if(m==0){ + res.push_back(v); + return; + } + if(begin==nums.size()){ + return; + } + v.push_back(nums[begin]); + subsetsCore(nums,begin+1,m-1); + v.pop_back(); + subsetsCore(nums,begin+1,m); + + } + vector v; + vector> res; +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/python/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.py" "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/python/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/python/038_02-\345\205\250\347\273\204\345\220\210-\344\270\215\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/87ba90075a0a54e867ee05a65612d6f00766624c9f50f92beb9004e8b5a3ff27-image.png" "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/87ba90075a0a54e867ee05a65612d6f00766624c9f50f92beb9004e8b5a3ff27-image.png" new file mode 100644 index 0000000..bce975e Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/img/readme.assets/87ba90075a0a54e867ee05a65612d6f00766624c9f50f92beb9004e8b5a3ff27-image.png" differ diff --git "a/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/readme.md" "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/readme.md" new file mode 100644 index 0000000..9abfa81 --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/readme.md" @@ -0,0 +1,287 @@ +# 038_03-全组合-含重复元素 + +tags: 全组合 + +--- + +## 题目原文 + +[leetcode链接]() + +给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + +**说明:**解集不能包含重复的子集。 + +**示例:** + +``` +输入: [1,2,2] +输出: +[ + [2], + [1], + [1,2,2], + [2,2], + [1,2], + [] +] +``` + + + +## 解题思路 + +### 迭代法 + +[参考](https://leetcode-cn.com/problems/subsets-ii/comments/) + +这道题相比上一道题多了去重的步骤,所以在看懂上一道题的情况下,这道题就是如何理解去重了。上一道题的解题介绍([78. Subsets](https://github.com/Kunwuwu/notes/blob/master/leetcode/78. Subsets.md)),下面讲解思路。 + +\> 以下思路基于元素列已经被排序。 + +1. 为什么会出现重复子列? + + - 该解法生成子列是在之前已经生成的所有子列上依次加上新的元素,生成新的子列。 + - 如果元素列(nums)中存在重复元素,则当前元素生成新子列的过程会与前面重复元素生成新子列的过程部分重复,则生成的子列也是部分重复的。 + +2. 重复子列出现在哪些部分? 假设元素列(nums)为:[1, 2, 2],下面进行模拟 + + - 遍历完第一个元素--->[[], [1]] + - 遍历完第二个元素--->[[], [1], [2], [1, 2]] + - 遍历完第三个元素--->[[], [1], [2], [1, 2], **[2]**, **[1, 2]**, [2, 2], [1, 2, 2]]。 + - ![image.png](img/readme.assets/87ba90075a0a54e867ee05a65612d6f00766624c9f50f92beb9004e8b5a3ff27-image.png) + + 加粗部分就是第三个元素遍历以后,产生的重复部分。[ **[2]**, **[1, 2]**]是因为第三个元素`2`,在与[[], [1]]生成新序列时生成的,可以看到这个过程与第二个元素`2`生成新序列的过程时一样的。即重复序列就是第三个元素在与[[], [1]]生成新序列时生成的,同时注意到[[], [1]]之后的序列就是第二元素遍历时生成的新序列,而第三个序列与这些新序列不会生成重复序列,同时注意每次生成的新序列的长度是可以被记录的。 + +3. 如何避免生成重复序列 在了解重复序列出现的原因和位置以后,就可以去重操作了。 + + - 先进行排序,保证重复元素挨在一起 + - 记录每次遍历生成的新序列的长度,这里用`left`表示每次遍历的开始位置,`right`结束位置,`len`表示上次新生成记录的长度 + - 根据与前面元素是否重复,来决定`left`的取值,也就是开始遍历的位置 + + + + 上述三个步骤就能有效避免当前元素与之前相同元素遍历过程发生重叠。 + + + + ```c++ + class Solution { + public: + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(), nums.end()); + vector> ans; + vector v; + ans.push_back(v); + int right = 1, left = 0, len = 0; + for (int i = 0; i < nums.size(); i++) { + if (i != 0 && (nums[i] == nums[i-1])) left = ans.size() - len; + else left = 0; + right = ans.size(); + len = right - left; + for (int j = left; j < right; ++j) { + v = ans[j]; + v.push_back(nums[i]); + ans.push_back(v); + } + } + return ans; + } + }; + ``` + + + + + + + + ### 位运算 + + [参考](https://leetcode-cn.com/problems/subsets-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-19/) + + 回顾一下,这个题的思想就是每一个数字,考虑它的二进制表示。 + + 例如,nums = [ 1, 2 , 3 ]。用 1 代表在,0 代表不在。 + + ``` + 1 2 3 + 0 0 0 -> [ ] + 0 0 1 -> [ 3] + 0 1 0 -> [ 2 ] + 0 1 1 -> [ 2 3] + 1 0 0 -> [1 ] + 1 0 1 -> [1 3] + 1 1 0 -> [1 2 ] + 1 1 1 -> [1 2 3] + ``` + + 但是如果有了重复数字,很明显就行不通了。例如对于 nums = [ 1 2 2 2 3 ]。 + + ``` + 1 2 2 2 3 + 0 1 1 0 0 -> [ 2 2 ] + 0 1 0 1 0 -> [ 2 2 ] + 0 0 1 1 0 -> [ 2 2 ] + ``` + + 上边三个数产生的数组重复的了。上面三个产生[2 2]的情况中我们只取其中 1 个,取哪个呢?取从重复数字的开头连续的情况。什么意思呢?就是下边的情况是我们所保留的。 + + ``` + 2 2 2 2 2 + 1 0 0 0 0 -> [ 2 ] + 1 1 0 0 0 -> [ 2 2 ] + 1 1 1 0 0 -> [ 2 2 2 ] + 1 1 1 1 0 -> [ 2 2 2 2 ] + 1 1 1 1 1 -> [ 2 2 2 2 2 ] + ``` + + 而对于 [ 2 2 ] 来说,除了 1 1 0 0 0 可以产生,下边的几种情况,都是产生的 [ 2 2 ] + + ``` + 2 2 2 2 2 + 1 1 0 0 0 -> [ 2 2 ] + 1 0 1 0 0 -> [ 2 2 ] + 0 1 1 0 0 -> [ 2 2 ] + 0 1 0 1 0 -> [ 2 2 ] + 0 0 0 1 1 -> [ 2 2 ] + ...... + ``` + + + + 怎么把 1 1 0 0 0 和上边的那么多种情况区分开来呢?我们来看一下出现了当前数字与前面数字重复的情况. 对于`1 1 0 0 0`重复数字的二进制表示前一位是1,保留, 对于剩下情况, 重复数字的二进制表示前一位是0, 舍弃. + + ``` + 对于 1 1 0 0 0 ,是 1。 + + 对于 1 0 1 0 0 , 是 0。 + + 对于 0 1 1 0 0 ,是 0。 + + 对于 0 1 0 1 0 ,是 0。 + + 对于 0 0 0 1 1 ,是 0。 + + ...... + ``` + + + + 可以看到只有第一种情况重复数字前一位对应的是 1 ,其他情况都是 0。其实除去从开头是连续的 1 的话,就是两种情况。 + + 第一种就是,占据了开头,类似于这种 10...1.... + + 第二种就是,没有占据开头,类似于这种 0...1... + + 这两种情况,除了第一位,其他位的 1 的前边一定是 0。所以的话,有重复数字时, 去除重复组合的条件是, 重复数字的前一位是0; + + 所以可以改代码了。 + + ``` + class Solution { + public: + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(),nums.end()); + int n = nums.size(); + int all = 1 << n; + vector> res;//存放最后的结果 + + for(int i = 0; i < all; i++){ + bool illegal=false; + vector vec; + for(int j = 0; j < nums.size(); j++){ + if((i & (1 << j)) != 0){ + if(j>0&&nums[j]==nums[j-1]&&(i&(1<<(j-1)))==0){ + illegal=true; + break; + } + else + { + vec.push_back(nums[j]); + } + } + } + if(!illegal){ + res.push_back(vec); + } + } + return res; + } + }; + ``` + + + + 或者 + + ```c++ + class Solution { + public: + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(),nums.end()); + int n = nums.size(); + int all = 1 << n; + vector> res;//存放最后的结果 + + for(int i = 0; i < all; i++){ + bool illegal=false; + vector vec; + for(int j = nums.size()-1; j>=0; j--){ + int bit_j=nums.size()-1-j; + if((i & (1 << bit_j)) != 0){ + if(bit_j>0&&nums[j]==nums[j+1]&&(i & (1 << (bit_j-1))) == 0){ + illegal=true; + break; + } + else + { + vec.push_back(nums[j]); + } + } + } + if(!illegal){ + res.push_back(vec); + } + } + return res; + } + }; + ``` + + + +## 代码 + +### [c++代码](./src/cpp/038_03-全组合-含重复元素.cpp) + +```c++ +class Solution { +public: + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(), nums.end()); + vector> ans; + vector v; + ans.push_back(v); + int right = 1, left = 0, len = 0; + for (int i = 0; i < nums.size(); i++) { + if (i != 0 && (nums[i] == nums[i-1])) left = ans.size() - len; + else left = 0; + right = ans.size(); + len = right - left; + for (int j = left; j < right; ++j) { + v = ans[j]; + v.push_back(nums[i]); + ans.push_back(v); + } + } + return ans; + } +}; +``` + +### [python代码](./src/python/038_03-全组合-含重复元素.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/cpp/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.cpp" "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/cpp/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.cpp" new file mode 100644 index 0000000..68ce6cb --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/cpp/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.cpp" @@ -0,0 +1,22 @@ +class Solution { +public: + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(), nums.end()); + vector> ans; + vector v; + ans.push_back(v); + int right = 1, left = 0, len = 0; + for (int i = 0; i < nums.size(); i++) { + if (i != 0 && (nums[i] == nums[i-1])) left = ans.size() - len; + else left = 0; + right = ans.size(); + len = right - left; + for (int j = left; j < right; ++j) { + v = ans[j]; + v.push_back(nums[i]); + ans.push_back(v); + } + } + return ans; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/python/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.py" "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/python/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240/src/python/038_03-\345\205\250\347\273\204\345\220\210-\345\220\253\351\207\215\345\244\215\345\205\203\347\264\240.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/img/readme.assets/1562643519616.png" "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/img/readme.assets/1562643519616.png" new file mode 100644 index 0000000..68c6fda Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/img/readme.assets/1562643519616.png" differ diff --git "a/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/readme.md" "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/readme.md" new file mode 100644 index 0000000..6d297a2 --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/readme.md" @@ -0,0 +1,65 @@ +# 038_04-对面和相等的正方体 + +tags: 全排列 + +--- + +## 题目原文 + + + +![1562643519616](img/readme.assets/1562643519616.png) + +## 代码 + +### [c++代码](./src/cpp/038_04-对面和相等的正方体.cpp) + +```c++ +#include +#include +using namespace std; +class Solution { +public: + vector> Permutation(vector nums) { + if (nums.empty()) + return res; + PermutationCore(nums, 0); + return res; + } + + void PermutationCore(vector nums, int begin) { + + if (begin == nums.size()) { + if (nums[0] + nums[1] + nums[2] + nums[3] == nums[4] + nums[5] + nums[6] + nums[7] && + nums[0] + nums[2] + nums[4] + nums[6] == nums[1] + nums[3] + nums[5] + nums[7] && + nums[0] + nums[1] + nums[4] + nums[5] == nums[2] + nums[3] + nums[6] + nums[7]) + res.push_back(nums); + return; + } + for (int i = begin; i> res; +}; +int main() { + Solution s; + vector nums{ 1,2,3,4,5,6,7,8 }; + s.Permutation(nums); + for (int i = 0; i < s.res.size(); i++) { + for (int j = 0; j < s.res[i].size(); j++) + cout << s.res[i][j]; + cout << endl; + } + system("pause"); + return 0; +} +``` + +### [python代码](./src/python/038_04-对面和相等的正方体.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/src/cpp/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223.cpp" "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/src/cpp/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223.cpp" new file mode 100644 index 0000000..c4d05d9 --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/src/cpp/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223.cpp" @@ -0,0 +1,41 @@ +#include +#include +using namespace std; +class Solution { +public: + vector> Permutation(vector nums) { + if (nums.empty()) + return res; + PermutationCore(nums, 0); + return res; + } + + void PermutationCore(vector nums, int begin) { + + if (begin == nums.size()) { + if (nums[0] + nums[1] + nums[2] + nums[3] == nums[4] + nums[5] + nums[6] + nums[7] && + nums[0] + nums[2] + nums[4] + nums[6] == nums[1] + nums[3] + nums[5] + nums[7] && + nums[0] + nums[1] + nums[4] + nums[5] == nums[2] + nums[3] + nums[6] + nums[7]) + res.push_back(nums); + return; + } + for (int i = begin; i> res; +}; +int main() { + Solution s; + vector nums{ 1,2,3,4,5,6,7,8 }; + s.Permutation(nums); + for (int i = 0; i < s.res.size(); i++) { + for (int j = 0; j < s.res[i].size(); j++) + cout << s.res[i][j]; + cout << endl; + } + system("pause"); + return 0; +} \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/src/python/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223.py" "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/src/python/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223/src/python/038_04-\345\257\271\351\235\242\345\222\214\347\233\270\347\255\211\347\232\204\346\255\243\346\226\271\344\275\223.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/img/readme.assets/1562639824505.png" "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/img/readme.assets/1562639824505.png" new file mode 100644 index 0000000..b6230b2 Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/img/readme.assets/1562639824505.png" differ diff --git "a/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/img/readme.assets/8-queens.png" "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/img/readme.assets/8-queens.png" new file mode 100644 index 0000000..1be6b68 Binary files /dev/null and "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/img/readme.assets/8-queens.png" differ diff --git "a/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/readme.md" "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/readme.md" new file mode 100644 index 0000000..203cb15 --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/readme.md" @@ -0,0 +1,95 @@ +# 038_05-N皇后 + +tags:全排列 + +--- + +## 题目原文 + +[leetcode链接](https://leetcode-cn.com/problems/n-queens/) + +n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + +![img](img/readme.assets/8-queens.png) + +上图为 8 皇后问题的一种解法。 + +给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + +每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + + + +## 解题思路 + +### 剑指offer + +![1562639824505](img/readme.assets/1562639824505.png) + +## 代码 + +### [c++代码](./src/cpp/038_05-N皇后.cpp) + +剑指offer的思路 + +```c++ +class Solution { +public: + vector> solveNQueens(int n) { + if(n<=0) + return res; + vector nums; + nums.resize(n); + for(int i=0;i &nums, int begin){ + if(begin==nums.size()){ + if(check(nums)) + draw(nums); + return; + } + for(int i=begin;i& nums){ + for(int i=0;i& nums){ + string temp(nums.size(),'.'); + vector v(nums.size(),temp); + for(int i=0;i> res; + + +}; +``` + +### [python代码](./src/python/038_05-N皇后.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/src/cpp/038_05-N\347\232\207\345\220\216.cpp" "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/src/cpp/038_05-N\347\232\207\345\220\216.cpp" new file mode 100644 index 0000000..6431b82 --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/src/cpp/038_05-N\347\232\207\345\220\216.cpp" @@ -0,0 +1,53 @@ +class Solution { +public: + vector> solveNQueens(int n) { + if(n<=0) + return res; + vector nums; + nums.resize(n); + for(int i=0;i &nums, int begin){ + if(begin==nums.size()){ + if(check(nums)) + draw(nums); + return; + } + for(int i=begin;i& nums){ + for(int i=0;i& nums){ + string temp(nums.size(),'.'); + vector v(nums.size(),temp); + for(int i=0;i> res; + + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/src/python/038_05-N\347\232\207\345\220\216.py" "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/src/python/038_05-N\347\232\207\345\220\216.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/038_05-N\347\232\207\345\220\216/src/python/038_05-N\347\232\207\345\220\216.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/readme.md" "b/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/readme.md" new file mode 100644 index 0000000..d0d93b5 --- /dev/null +++ "b/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/readme.md" @@ -0,0 +1,312 @@ +# 039-数组中出现次数超过一半的数字 + +tags: 数组 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/029-%E6%95%B0%E7%BB%84%E4%B8%AD%E5%87%BA%E7%8E%B0%E6%AC%A1%E6%95%B0%E8%B6%85%E8%BF%87%E4%B8%80%E5%8D%8A%E7%9A%84%E6%95%B0%E5%AD%97](https://github.com/gatieme/CodingInterviews/tree/master/029-数组中出现次数超过一半的数字)) + +### 思路1排序以后统计个数 + +如果是排序好的数组,那么我们就很容易统计每个数组出现的次数,而题目中并没有说数组是排序好的,因此我们需要先排序(最好的情况下$O(nlogn)$),后统计(一次遍历即可$O(n)$),因此这种方法的时间复杂度为$O(nlogn)$ + +### 思路2 基于Partition函数的$O(n)$的查找第K大的数 + +上面基于排序的算法比较保守,因为它没有充分利用**出现次数超过一半**这个条件。 + +数组中有一个数字出现的次数超过了数组长度的一半,那么**如果我们把这个数组排序,那么排序之后位于数组中间的那个数字一定就是那个出现次数超过数组长度一半的数字** + +也就是说这个数字其实就是统计学上的中位数,即长度为N的数组中的$N/2$大的元素,因此我们的题目最后成为返回数组中第K($K=Len/2$)大的数。 + +因此我们的问题成为**查找一个数组中的K大的元素** + +我们写过**快速排序算法**,其中的Partition()方法是一个最重要的方法,该方法返回一个index,能够保证index位置的数是已排序完成的,在index左边的数都比index所在的数小,在index右边的数都比index所在的数大。那么本题就可以利用这样的思路来解。 + +1. 通过Partition()返回index,如果index==mid,那么就表明找到了数组的中位数;如果indexmid,表明中位数在[start,index-1]之间。知道最后求得index==mid循环结束。 +2. 根据求得的index,遍历一遍数组,每当出现一个等于index所指向的数时time++,最后判断time是否大于数组长度的一半,如果大于则表明index所指向的数就是所求的数,如果不是,则表明不存在一个数出现的次数超过数组长度的一半。 + +**注意:** 这种方法会改变数组, 如果面试官不允许, 则不能使用 + +```c++ +class Solution { +public: + int MoreThanHalfNum_Solution(vector numbers) { + if(numbers.empty()) + return 0; + int length=numbers.size(); + int middle=length>>1; + int start=0; + int end=length-1; + int index=Partion(numbers,start,end); + while(index!=middle){ + if(index>middle){ + end=index-1; + index=Partion(numbers,start,end); + } + if(indexmiddle) + return numbers[middle]; + else + return 0; + } + + int Partion(vector& numbers, int start, int end ){ + if(numbers.empty()||start<0||end<0||start>end) + throw new std::logic_error("invalid input"); + int index=RandomInRange(start,end); + int small=start-1; + swap(numbers[index],numbers[end]); + for(int i=start;i 数组中有一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现的次数之和还要多 +> +> 我们考虑**阵地攻守(镇守阵地),遇见一个友军就抱成团,遇见一个敌军就同归于尽,那么最后战场上剩余的肯定就是人数(出现次数)最多的那个队伍(数字)** + +采用**阵地攻守**的思想 + +- 第一个数字作为第一个士兵,守阵地;count = 1; +- 遇到相同元素,count++; 遇到不相同元素,即为敌人,同归于尽,count--; +- 当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。 +- 再加一次循环,记录这个士兵的个数看是否大于数组一般即可。 + +由于我们要找的数字出现的次数比他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字,因为少的元素都已经阵亡了,战场上仅剩下的一定是人数数目要多的那个队伍 + +```c++ +class Solution { +public: + int MoreThanHalfNum_Solution(vector numbers) { + if(numbers.empty()) + return 0; + int times=1; + int res=numbers[0]; + for(int i=1;inumbers.size()/2) + return res; + else + return 0; + } +}; +``` + +这个思想有一个简单的实现变种,就是现的次数超过数组长度的一半,表明这个数字出现的次数比其他数字出现的次数的总和还多。 + +所以我们可以考虑每次删除两个不同的数,那么在剩下的数中,出现的次数仍然超过总数的一半。通过不断重复这个过程,不断排除掉其它的数,最终找到那个出现次数超过一半的数字。这个方法, + +> 例:数组 a[5]={0,1,2,1,1}; 我们要查找的数字为1,操作步骤为:遍历整个数组,然后每次删除不同的两个数字,过程如下: 0 1 2 1 1 =>2 1 1=>1 + +具体实现:我们在考虑删除两个不同的数字的时候,实际上可以同过计数来实现,而不是物理上真正的删除。 在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。 + +### 使用STL的count函数统计某个值出现的次数 + +STL的count函数原型如下 + +```c++ +template inline + size_t count( + InputIterator First, + InputIterator Last, + const T& Value +) +``` + +algorithm头文件定义了一个count的函数,其功能类似于find。 这个函数使用一对迭代器和一个值做参数,返回这个值出现次数的统计结果。 count只能统计某个特定元素出现的次数,不够灵活,因此STL提供了count_if,前两个参数是iterator(迭代器),表示查找半闭合区间的前后两个位置,第三个参数为一个用户定义的predicate function object,而predicate意思就是说是一个返回值是bool型的仿函数(function object,也称functor)。 + +```c++ +template inline +typename iterator_traits<_InIt>::difference_type +count_if(_InIt _First, _InIt _Last, _Pr _Pred); +``` + +核心代码: + +```c++ +class Solution +{ +public: + int MoreThanHalfNum_Solution(vector numbers) + { +// return numbers.empty( ) ? 0 : *find_if(numbers.begin( ), numbers.end( ),[numbers](int x) +// { +// return (count(numbers.begin( ),numbers.end( ), x) * 2) > numbers.size(); +// }); + + if(numbers.size( ) == 0) + { + return 0; + } + for(int i = 0 ; i < numbers.size( ); i++) + { + debug <<"num = " <second <second * 2 > nsize) + { + return it->first; + } + } + return 0; + } +}; +``` + +## 变种以及扩展 + +昨天看到了扩展问题, + +- **如果有且只有一个的出现最多的那个数字出现的次数是数组长度的一半呢?又或者是一半减1?** + +我们还是继续从我们之前的那道超过一半的数来入手,我们的"阵地攻守"的解法是每遇到2个不同的数,就删除,剩下的就是那个出现次数超过一半的数字。 + +这个方法对于超过一半的情况可以成立,对于扩展问题就不再行得通了。 + +但是他们的本质是相同的, + +- 对于一个长度为2n的数组,如果有个数出现次数超过n,那么至少有1组,连续2个数是重复的相应的,于是"阵地攻守"中每次不同的元素就删除(同归于尽)就可以找到那个元素 +- 如果出现的次数为n, 那么至少有一组连续3个数是重复。每3个不重复的数删除一次 +- 如果是n-1, 就是一组至少有连续4个数重复。每4个不重复的数删除一次 + +> 参考 +> +> [编程之美系列之二——寻找出现频率超过一半的数](http://www.cnblogs.com/jy02414216/archive/2011/03/04/1970497.html) +> +> [微软面试100题(74):数组中出现次数超过长度的一半/一半减一的元素](http://blog.chinaunix.net/uid-26456800-id-3383003.html) + +## 代码 + +### [c++代码](./src/cpp/039-数组中出现次数超过一半的数字.cpp) + +```c++ +class Solution { +public: + int MoreThanHalfNum_Solution(vector numbers) { + if(numbers.empty()) + return 0; + int times=1; + int res=numbers[0]; + for(int i=1;inumbers.size()/2) + return res; + else + return 0; + } +}; +``` + +### [python代码](./src/python/039-数组中出现次数超过一半的数字.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/src/cpp/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.cpp" "b/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/src/cpp/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.cpp" new file mode 100644 index 0000000..77e46c0 --- /dev/null +++ "b/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/src/cpp/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.cpp" @@ -0,0 +1,29 @@ +class Solution { +public: + int MoreThanHalfNum_Solution(vector numbers) { + if(numbers.empty()) + return 0; + int times=1; + int res=numbers[0]; + for(int i=1;inumbers.size()/2) + return res; + else + return 0; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/src/python/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.py" "b/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/src/python/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227/src/python/039-\346\225\260\347\273\204\344\270\255\345\207\272\347\216\260\346\254\241\346\225\260\350\266\205\350\277\207\344\270\200\345\215\212\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/040-\346\234\200\345\260\217\347\232\204K\344\270\252\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/040-\346\234\200\345\260\217\347\232\204K\344\270\252\346\225\260/readme.md" new file mode 100644 index 0000000..67bb96f --- /dev/null +++ "b/\345\211\221\346\214\207offer/040-\346\234\200\345\260\217\347\232\204K\344\270\252\346\225\260/readme.md" @@ -0,0 +1,163 @@ +# 040-最小的K个数 + +tags: 数组 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=13&tqId=11182&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 + +## 解题思路 + +[参考](https://www.cnblogs.com/edisonchou/p/4799678.html) + +### 需要修改数据源的O(n)解法 + +基于快速排序中的**Partition**函数来解决这个问题。如果基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。 + +  But,采用这种思路是**有限制的**。我们**需要修改输入的数组**,因为函数Partition会调整数组中数字的顺序。 + +```c++ +class Solution { +public: + vector GetLeastNumbers_Solution(vector input, int k) { + vector res; + if(k<1||input.size()k-1){ + end=index-1; + index=Partion(input,start,end); + } + else{ + start=index+1; + index=Partion(input,start,end); + } + } + for(int i=0;i& input, int start, int end){ + if(input.empty()||start<0||end<0||start>end) + throw new std::logic_error("invalid input"); + int index=RandomInrange(start,end); + int small=start-1; + swap(input[index],input[end]); + for(int i=start;i> IntSet; + typedef multiset>::iterator setIterator; + + vector GetLeastNumbers_Solution(vector input, int k) { + vector res; + if(k<1||input.size()和less](https://www.cnblogs.com/lzhu/p/7010894.html) + +## 代码 + +### [c++代码](./src/cpp/040-最小的K个数.cpp) + +```c++ +class Solution { +public: + typedef multiset> IntSet; + typedef multiset>::iterator setIterator; + + vector GetLeastNumbers_Solution(vector input, int k) { + vector res; + if(k<1||input.size()> IntSet; + typedef multiset>::iterator setIterator; + + vector GetLeastNumbers_Solution(vector input, int k) { + vector res; + if(k<1||input.size() [数据结构:堆(Heap)](https://www.jianshu.com/p/6b526aa481b1) +> +> [数据结构——堆(Heap)大根堆、小根堆](https://www.cnblogs.com/wangchaowei/p/8288216.html) +> +> [8-玩转数据结构-堆](https://cloud.tencent.com/developer/article/1192923) + +我们将数据分为两部分,位于左边最大堆的数据比右边最小堆的数据要小,左、右两边内部的数据没有排序,也可以根据左边最大的数及右边最小的数得到中位数。 + +接下来考虑用最大堆和最小堆实现的一些细节。 + +首先要保证数据平均分配到两个堆中,因此两个堆中数据的数目之差不能超过1.为了实现平均分配,可以在数据的总数目是偶数时把新数据插入到最小堆中,否则插入到最大堆中。 + +此外,还要保证最大堆中所有数据小于最小堆中数据。所以,新传入的数据需要先和最大堆的最大值或者最小堆中的最小值进行比较。以总数目为偶数为例,按照我们制定的规则,新的数据会被插入到最小堆中,但是在这之前,我们需要判断这个数据和最大堆中的最大值谁更大,如果最大堆中的数据比较大,那么我们就需要把当前数据插入最大堆,然后弹出新的最大值,再插入到最小堆中。由于最终插入到最小堆的数字是原最大堆中最大的数字,这样就保证了最小堆中所有数字都大于最大堆的数字。 + +## 知识点 + +### 最大堆 最小堆 + +[参考](https://www.jianshu.com/p/6b526aa481b1) + +#### 堆属性 + +堆分为两种:*最大堆*和*最小堆*,两者的差别在于节点的排序方式。 + +在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。 + +例子: + + + +![img](https:////upload-images.jianshu.io/upload_images/4064751-14a6cde25bdff968.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/190/format/webp) + + + +这是一个最大堆,,因为每一个父节点的值都比其子节点要大。`10` 比 `7` 和 `2` 都大。`7` 比 `5` 和 `1`都大。 + +根据这一属性,那么最大堆总是将其中的最大值存放在树的根节点。而对于最小堆,根节点中的元素总是树中的最小值。堆属性非常的有用,因为堆常常被当做优先队列使用,因为可以快速的访问到“最重要”的元素。 + +> **注意:**堆的根节点中存放的是最大或者最小元素,但是其他节点的排序顺序是未知的。例如,在一个最大堆中,最大的那一个元素总是位于 index 0 的位置,但是最小的元素则未必是最后一个元素。--唯一能够保证的是最小的元素是一个叶节点,但是不确定是哪一个。 + +#### 来自数组的树 + +用数组来实现树相关的数据结构也许看起来有点古怪,但是它在时间和空间山都是很高效的。 + +我们准备将上面的例子中的树这样存储: + +``` +[ 10, 7, 2, 5, 1 ] +``` + +就这多!我们除了一个简单的数组以外,不需要任何额外的空间。 + +如果我们不允许使用指针,那么我们怎么知道哪一个节点是父节点,哪一个节点是它的子节点呢?问得好!节点在数组中的位置index 和它的父节点已经子节点的索引之间有一个映射关系。 + +如果 `i` 是节点的索引,那么下面的公式就给出了它的父节点和子节点在数组中的位置: + +``` +parent(i) = floor((i - 1)/2) +left(i) = 2i + 1 +right(i) = 2i + 2 +``` + +注意 `right(i)` 就是简单的 `left(i) + 1`。左右节点总是处于相邻的位置。 + + + +### STL + +参考: + +> [make_heap(), pop_heap(), push_heap()用法](https://blog.csdn.net/qq_29630271/article/details/66478256) +> +> [STL--heap概述:make_heap,sort_heap,pop_heap,push_heap](https://www.cnblogs.com/likui360/p/6364896.html) + +![1562748867523](img/readme.assets/1562748867523.png) + +## 代码 + +### [c++代码](./src/cpp/041-数据流中的中位数.cpp) + +```c++ +class Solution { +public: + void Insert(int num) + { + if(((max.size()+min.size())&1)==0){// 堆的总长度为偶数时, 添加新元素到最小堆 + if(max.size()>0&&num()); + num=max[0]; + pop_heap(max.begin(),max.end(),less()); + max.pop_back(); + } + min.push_back(num); + push_heap(min.begin(),min.end(),greater()); + }else{// 堆的总长度为奇数时, 添加新元素到最大堆 + if(min.size()>0&&num>min[0]){ + min.push_back(num); + push_heap(min.begin(),min.end(),greater()); + num=min[0]; + pop_heap(min.begin(),min.end(),greater()); + min.pop_back(); + } + max.push_back(num); + push_heap(max.begin(),max.end(),less()); + } + } + + double GetMedian() + { + int size=max.size()+min.size(); + double res=0; + if(size==0) + throw new std::logic_error("invalid input"); + if((size&1)==0) + res=(max[0]+min[0])/2.;//这里要注意整数和整数相除结果是整数, 所以应该除以2. + else + res=min[0];//因为先从最小堆开始放, 如果数据总长度是奇数, 那么最后一个元素一定在最小堆 + return res; + } + + vector max;//最大堆 + vector min;//最小堆 +}; +``` + +### [python代码](./src/python/041-数据流中的中位数.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/src/cpp/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.cpp" "b/\345\211\221\346\214\207offer/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/src/cpp/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.cpp" new file mode 100644 index 0000000..976e4aa --- /dev/null +++ "b/\345\211\221\346\214\207offer/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/src/cpp/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.cpp" @@ -0,0 +1,43 @@ +class Solution { +public: + void Insert(int num) + { + if(((max.size()+min.size())&1)==0){// 堆的总长度为偶数时, 添加新元素到最小堆 + if(max.size()>0&&num()); + num=max[0]; + pop_heap(max.begin(),max.end(),less()); + max.pop_back(); + } + min.push_back(num); + push_heap(min.begin(),min.end(),greater()); + }else{// 堆的总长度为奇数时, 添加新元素到最大堆 + if(min.size()>0&&num>min[0]){ + min.push_back(num); + push_heap(min.begin(),min.end(),greater()); + num=min[0]; + pop_heap(min.begin(),min.end(),greater()); + min.pop_back(); + } + max.push_back(num); + push_heap(max.begin(),max.end(),less()); + } + } + + double GetMedian() + { + int size=max.size()+min.size(); + double res=0; + if(size==0) + throw new std::logic_error("invalid input"); + if((size&1)==0) + res=(max[0]+min[0])/2.;//这里要注意整数和整数相除结果是整数, 所以应该除以2. + else + res=min[0];//因为先从最小堆开始放, 如果数据总长度是奇数, 那么最后一个元素一定在最小堆 + return res; + } + + vector max;//最大堆 + vector min;//最小堆 +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/src/python/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.py" "b/\345\211\221\346\214\207offer/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/src/python/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/src/python/041-\346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/img/readme.assets/dp.png" "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/img/readme.assets/dp.png" new file mode 100644 index 0000000..942ce18 Binary files /dev/null and "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/img/readme.assets/dp.png" differ diff --git "a/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/readme.md" "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/readme.md" new file mode 100644 index 0000000..8a9ce85 --- /dev/null +++ "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/readme.md" @@ -0,0 +1,204 @@ +# 042-连续子数组的最大和 + +tags: 贪婪算法 动态规划 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/459bd355da1549fa8a49e350bf3df484?tpId=13&tqId=11183&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/031-%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%A4%A7%E5%92%8C](https://github.com/gatieme/CodingInterviews/tree/master/031-连续子数组的最大和)) + +### 动态规划 + +解体思路: + +如果用函数f(i)表示以第i个数字结尾的子数组的最大和,那么我们需要求出max(f[0...n])。我们可以给出如下递归公式求f(i) + +[![dp思想](img/readme.assets/dp.png)](https://github.com/gatieme/CodingInterviews/blob/master/031-连续子数组的最大和/dp.png) + +这个公式的意义: + +1. 当以第(i-1)个数字为结尾的子数组中所有数字的和f(i-1)小于0时,如果把这个负数和第i个数相加,得到的结果反而不第i个数本身还要小,所以这种情况下最大子数组和是第i个数本身。 +2. 如果以第(i-1)个数字为结尾的子数组中所有数字的和f(i-1)大于0,与第i个数累加就得到了以第i个数结尾的子数组中所有数字的和 + +```c++ +class Solution{ + int dp[1000]; +public: + int FindGreatestSumOfSubArray(vector array){ + if(array.size( ) == 0) + return 0; + int maxSum = INT_MIN; + dp[0] = array[0]; + + for(unsigned int i = 1; i < array.size( ); i++) + { + if(dp[i - 1] <= 0) + dp[i] = array[i]; + else + dp[i] = array[i] + dp[i - 1]; + + if(dp[i] > maxSum) + maxSum = dp[i]; + } + return maxSum; + } +}; +``` + + + +### 贪婪思想 + +> 如果希望达到O(n)时间复杂度,我们就应该能够想到我们只能对整个数组进行一次扫描,在扫描过程中求出最大连续子序列和以及子序列的起点和终点位置。 + +假如输入数组为{1,-2,3,10,-4,7,2,-5},我们尝试从头到尾累加其中的正数, + +初始化和为0,第一步加上1,此时和为1,第二步加上-2,此时和为-1,第三步加上3,此时我们发现-1+3=2,最大和2反而比3一个单独的整数小,这是因为3加上了一个负数,发现这个规律以后我们就重新作出累加条件 + +这个方法其实就是动态规划算法的改进 + +- 如果当前和为负数,那么就放弃前面的累加和,从数组中的下一个数再开始计数 +- 否则我们就继续累计,并且保存当前最大的累计和 + +```c++ +class Solution +{ +public: + int FindGreatestSumOfSubArray(vector array) + { + if(array.size( ) == 0) + return 0; + + int sum = 0, maxSum = INT_MIN; + + for(int i = 0; i < array.size( ); i++) + { + sum += array[i]; + debug < maxSum) /// 否则的话累计当前和 + maxSum = sum; + } + return maxSum; + } +}; +``` + +但是这个有一个问题,如果整个数组的数据全是负数,那么我们的maxSum无法进行累计,最后仍为0。 + +这个问题怎么解决呢? + +整个数组全是负数,那么最大值也是负数,而这个最大值正好是数组连续子数组的最大和,因此我们维护一个最大值maxNum,即可 + +- 如果maxNum<0,我们就直接返回maxNum +- 如果maxNum>0,那么我们就返回累计的maxSum + +``` +return (maxNum > 0) ? maxSum : maxNum; +``` + +完整代码如下 + +```c++ +class Solution{ +public: + int FindGreatestSumOfSubArray(vector array) + { + if(array.size( ) == 0) + return 0; + + int maxNum = INT_MIN; + int sum = 0, maxSum = INT_MIN; + + for(int i = 0; i < array.size( ); i++) + { + sum += array[i]; + debug < maxSum) /// 否则的话累计当前和 + maxSum = sum; + /// 保存数据中的最大值 + /// 这种情况下是为了排除整个数组全为负数的特殊情况 + if(array[i] > maxNum) + maxNum = array[i]; + } + /// 如果数组最大值大于0, 那么我们就直接返回累计的最大和 + /// 如果数组最大值为负数, 说明整个数组都是负数, 那么就返回数组最大值 + return (maxNum > 0) ? maxSum : maxNum; + } +}; +``` + +但是其实有更好的办法,每次弄完后我们无需设置那个sum置为0,而是需要从新的位置(下一个位置)开始,因此此时其实sum=array[i + 1]; + +那么我们直接用下面的代码即可 + +```c++ +class Solution +{ +public: + int FindGreatestSumOfSubArray(vector array) + { + if(array.empty()) + throw new std::logic_error("invalid input"); + int sum=0; + int maxSum=INT_MIN; + + for(int i=0;imaxSum) + maxSum=sum; + } + return maxSum; + } +}; +``` + + + +## 代码 + +### [c++代码](./src/cpp/042-连续子数组的最大和.cpp) + +```c++ +class Solution +{ +public: + int FindGreatestSumOfSubArray(vector array) + { + if(array.empty()) + throw new std::logic_error("invalid input"); + int sum=0; + int maxSum=INT_MIN; + + for(int i=0;imaxSum) + maxSum=sum; + } + return maxSum; + } +}; +``` + +### [python代码](./src/python/042-连续子数组的最大和.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/src/cpp/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.cpp" "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/src/cpp/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.cpp" new file mode 100644 index 0000000..72b212c --- /dev/null +++ "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/src/cpp/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.cpp" @@ -0,0 +1,21 @@ +class Solution +{ +public: + int FindGreatestSumOfSubArray(vector array) + { + if(array.empty()) + throw new std::logic_error("invalid input"); + int sum=0; + int maxSum=INT_MIN; + + for(int i=0;imaxSum) + maxSum=sum; + } + return maxSum; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/src/python/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.py" "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/src/python/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214/src/python/042-\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\222\214.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/readme.md" new file mode 100644 index 0000000..1dc32db --- /dev/null +++ "b/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/readme.md" @@ -0,0 +1,153 @@ +# 043-从1到n整数中1出现的次数 + +tags: 递归 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/bd7f978302044eee894445e244c7eee6?tpId=13&tqId=11184&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。 + +## 解题思路 + +### 暴力方法 + +最简单直接的方法就是我们循环所有的1~n中的每个number,计算每个number出现的次数 + +```c++ +class Solution { +public: + int NumberOf1Between1AndN_Solution(int n) + { + if(n<=0) + return 0; + int times=0; + for(int i=1;i<=n;i++){ + times+=NumberOf1(i); + } + return times; + } + int NumberOf1(int num){ + int times=0; + while(num!=0){ + if(num%10==1) + times++; + num=num/10; + } + return times; + } +}; +``` + + + +### 方法一 剑指offer的递归版本 + +链接:https://www.nowcoder.com/questionTerminal/bd7f978302044eee894445e244c7eee6来源:牛客网 + + 以21345为例分析。把从1到21345的所有数字分为两段,一段是从1到1345,另一段是从1346到21345。 + + 先看从1346到21345中1出现的次数。1的出现分为两种情况。首先分析1出现在最高位的情况。从1346到21345的数字中,1出现在10000~19999这10000个数字的万位中,一共出现了10000个。 + + 但是并不是对所有5位数而言在万位出现的次数都是10000个,比如12345,1只出现在10000~12345的万位,出现的次数是2346次,也就是除去最高位数字之后剩下的数字再加上1。 + + 接下来分析1出现在除最高位之外的其他四位数中的情况,也就是例子中1346~21345这20000个数字中后4位中1出现的次数。书中说2000次,我认为书中此处有误。由于最高位是2,可以再把1346~21345分成两段:1346~11345和11346~21345。每一段剩下的4位数字中,选择其中一位是1,总共有C4 1种情况,其余3位可以在0-9这10个数字中任意选择,也就是4*10^3=4000次。也许有人会说:这样会有重复的情况出现啊?对,如果重复一次是存在两个1,重复两次是存在三个1,重复三次是存在4个1,也就是重复的次数就是四位数中1多于一个的个数,这正是我们想要的。那么总共出现的次数是2*4000=8000次。 + + 至于从1到1345中1出现的次数,可以按照上面的方法求得。以此类推,就得出总共1的个数。代码如下: + +```c++ +public class Solution { + public int NumberOf1Between1AndN_Solution(int n) { + if (n <= 0) { + return 0; + } + int tenPow; // 10的倍数,用于分离高位和低位 + int pow; // 10的倍数的位数 + int hi; // 高1位 + int lo; // 低位 + int count = 0; // 总数 + for (tenPow = 1, pow = 0; tenPow * 10 <= n; tenPow *= 10, pow++); // 求出最高位的位数和对应的10的倍数 + while (tenPow > 0) { + hi = (n / tenPow) % 10; // 取高1位 + lo = n % tenPow; // 取低位 + if (hi > 1) { + count += tenPow; // 高1位大于1时有该位对应的10的倍数个1出现 + } else if (hi == 1) { + count += lo + 1; // 高1位等于1时有低位的数+1个1出现 + } + count += tenPow / 10 * hi * pow; // 低位的数有多少个1出现 + tenPow /= 10; + pow--; + } + return count; + } +} +``` + + + +### 方法二 代码简洁但不好理解 + +[参考](https://www.nowcoder.com/questionTerminal/bd7f978302044eee894445e244c7eee6) + +主要思路:设定整数点(如1、10、100等等)作为位置点i(对应n的各位、十位、百位等等),分别对每个数位上有多少包含1的点进行分析 + +根据设定的整数位置,对n进行分割,分为两部分,高位n/i,低位n%i + +当i表示百位,且百位对应的数>=2,如n=31456,i=100,则a=314,b=56,此时百位为1的次数有a/10+1=32(最高两位0~31),每一次都包含100个连续的点,即共有(a%10+1)*100个点的百位为1 + +当i表示百位,且百位对应的数为1,如n=31156,i=100,则a=311,b=56,此时百位对应的就是1,则共有a%10(最高两位0-30)次是包含100个连续点,当最高两位为31(即a=311),本次只对应局部点00~56,共b+1次,所有点加起来共有(a%10*100)+(b+1),这些点百位对应为1 + +当i表示百位,且百位对应的数为0,如n=31056,i=100,则a=310,b=56,此时百位为1的次数有a/10=31(最高两位0~30) + +综合以上三种情况,当百位对应0或>=2时,有(a+8)/10次包含所有100个点,还有当百位为1(a%10==1),需要增加局部点b+1 + +之所以补8,是因为当百位为0,则a/10==(a+8)/10,当百位>=2,补8会产生进位位,效果等同于(a/10+1) + +```c++ +class Solution { +public: + int NumberOf1Between1AndN_Solution(int n) + { + int ones = 0; + //m表示当前分析的是哪一个数位 + for (long long m = 1; m <= n; m *= 10) { + int a = n/m, b = n%m; + ones += (a + 8) / 10 * m + (a % 10 == 1) * (b + 1); + } + return ones; + } + +}; +``` + + + +## 代码 + +### [c++代码](./src/cpp/043-从1到n整数中1出现的次数.cpp) + +```c++ +class Solution { +public: + int NumberOf1Between1AndN_Solution(int n) + { + int ones = 0; + //m表示当前分析的是哪一个数位 + for (long long m = 1; m <= n; m *= 10) { + int a = n/m, b = n%m; + ones += (a + 8) / 10 * m + (a % 10 == 1) * (b + 1); + } + return ones; + } + +}; +``` + +### [python代码](./src/python/043-从1到n整数中1出现的次数.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/src/cpp/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.cpp" "b/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/src/cpp/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.cpp" new file mode 100644 index 0000000..a7d9746 --- /dev/null +++ "b/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/src/cpp/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.cpp" @@ -0,0 +1,14 @@ +class Solution { +public: + int NumberOf1Between1AndN_Solution(int n) + { + int ones = 0; + //m表示当前分析的是哪一个数位 + for (long long m = 1; m <= n; m *= 10) { + int a = n/m, b = n%m; + ones += (a + 8) / 10 * m + (a % 10 == 1) * (b + 1); + } + return ones; + } + +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/src/python/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" "b/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/src/python/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260/src/python/043-\344\273\2161\345\210\260n\346\225\264\346\225\260\344\270\2551\345\207\272\347\216\260\347\232\204\346\254\241\346\225\260.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/readme.md" "b/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/readme.md" new file mode 100644 index 0000000..068f9d2 --- /dev/null +++ "b/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/readme.md" @@ -0,0 +1,87 @@ +# 044-数字序列中某一位的数字 + +tags: 找规律 + +--- + +## 题目原文 + +[AcWing链接](https://www.acwing.com/problem/content/description/52/) + +数字以0123456789101112131415…的格式序列化到一个字符序列中。 + +在这个序列中,第5位(从0开始计数)是5,第13位是1,第19位是4,等等。 + +请写一个函数求任意位对应的数字。 + +## 解题思路 + +[参考](https://www.cnblogs.com/wangkundentisy/p/8963605.html) + +《剑指offer》上提供了两种思路。 + +方法1: + +第一种思路是:从0开始枚举每个数字。每枚举一个数字的时候,求出该数字是几位(如15是2位数、9323是4位数),并把该数字的位数和前面所有数字的位数累加。如果位数之和仍然小于等于n,则继续枚举下一个数字。当累加的数位大于n时,那么第n位数字一定在这个数字里。(此处为什么是大于而不是大于等于?因为是从0开始计数的,实质应为第n+1位)该算法的时间复杂度为O(N),当N很大时(如N = 10 ^ 11)往往会超时。 + +方法2; + +这种方法是本文论述的重点,其实本提可以采用和文章http://www.cnblogs.com/wangkundentisy/p/8920147.html中的第二题的方法4类似。我们令f(m)表示"从0~长度为m的最大的数字"的数字个数之和,由此我们可以继续分析: + +f(0) = 0 + +f(1) =10 + 0 = 10 (对应0 ~ 9) + +f(2) =90 * 2 + f(1) = 190 (对应10 ~99, 0 ~ 9) + +f(3) =900 * 3 + f(2) = 2890 (对应100 - 999,0 ~ 99) + +f(4) = 9000 * 4 + f(3) =38890 (对应1000 ~ 9999,0 ~ 999) + +.... + +f(m) = 9 * 10^(i - 1) * m + f(m-1) + +其中m表示数字的长度。求出f(m)之后,剩下的就比较好解了。 + +对于数字n,我们只需要比较n与数组f中每个元素,如果f(k) >= n,其中k是满足前面条件的最小值,那么我们就可以确定最终的数字长度一定是k了。所以令n = n - f(k - 1),然后根据n / k和n % k的结果,就能知道最终的数字R和R中的哪个位置。 + +举个例子: + +假设 n = 1001,由于f(2) < 1001且f(3) > 1001,所以最终的数字一定是3位数的数字。令n = n - f(2) = 811。有811 / 3 =270 ,811 % 3 = 1。所以最终的数字为100 + 270 = 370,且是370中的第1位数(从0开始计数),所以最终的结果是7。 + +## 代码 + +### [c++代码](./src/cpp/044-数字序列中某一位的数字.cpp) + +```c++ +class Solution { +public: + int digitAtIndex(int n) { + if(n<=0) + return 0; + long long i=1,s=9,base=1; + while(n>i*s){ + if(i==1) + n-=10; + else + n-=i*s; + i++; + s=s*10; + base=base*10; + } + if(i==1) + n=n-1; + int number=base+n/i; + int r=n%i; + for(int j=i-r;j>1;j--) number/=10; + return number%10; + } +}; +``` + +### [python代码](./src/python/044-数字序列中某一位的数字.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/src/cpp/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227.cpp" "b/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/src/cpp/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227.cpp" new file mode 100644 index 0000000..c30dd60 --- /dev/null +++ "b/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/src/cpp/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227.cpp" @@ -0,0 +1,23 @@ +class Solution { +public: + int digitAtIndex(int n) { + if(n<=0) + return 0; + long long i=1,s=9,base=1; + while(n>i*s){ + if(i==1) + n-=10; + else + n-=i*s; + i++; + s=s*10; + base=base*10; + } + if(i==1) + n=n-1; + int number=base+n/i; + int r=n%i; + for(int j=i-r;j>1;j--) number/=10; + return number%10; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/src/python/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227.py" "b/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/src/python/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227/src/python/044-\346\225\260\345\255\227\345\272\217\345\210\227\344\270\255\346\237\220\344\270\200\344\275\215\347\232\204\346\225\260\345\255\227.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/045-\346\212\212\346\225\260\347\273\204\346\216\222\346\210\220\346\234\200\345\260\217\347\232\204\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/045-\346\212\212\346\225\260\347\273\204\346\216\222\346\210\220\346\234\200\345\260\217\347\232\204\346\225\260/readme.md" new file mode 100644 index 0000000..0692994 --- /dev/null +++ "b/\345\211\221\346\214\207offer/045-\346\212\212\346\225\260\347\273\204\346\216\222\346\210\220\346\234\200\345\260\217\347\232\204\346\225\260/readme.md" @@ -0,0 +1,162 @@ +# 045-把数组排成最小的数 + +tags: 排序 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/8fecd3f8ba334add803bf2a06af1b993?tpId=13&tqId=11185&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/033-%E6%8A%8A%E6%95%B0%E7%BB%84%E6%8E%92%E6%88%90%E6%9C%80%E5%B0%8F%E7%9A%84%E6%95%B0](https://github.com/gatieme/CodingInterviews/tree/master/033-把数组排成最小的数)) + +首先因为数组可能非常长,所以要定义一个整数类,使得其大小可以容纳所有的数组元素组成的数不大现实。因此我们直接输出这个数组,让其看起来像一个整数,这样我们就可以把问题转化为:如何给这个数组排序,使其看做一个数字的时候最小。 第一个想到的可能是按字典序排序,小的在前面。可惜这个是不可行的,比如32的字典序比322小,但是32322比32232大, 所以在这里自定义一个比较大小的函数,比较两个字符串s1, s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大,如果s1+s2大,那说明s2应该放前面,所以按这个规则,s2就应该排在s1前面。 + +思路:先将整数数组转为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可。这里注意的是字符串的比较函数需要重新定义,不是比较a和b,而是比较ab与 ba。如果ab < ba,则a < b;如果ab > ba,则a > b;如果ab = ba,则a = b。比较函数的定义是本解决方案的关键。这道题其实就是希望我们能找到一个排序规则,根据这个规则排出来的数组能排成一个最小的数字。 + +## 知识点 + +### sort函数 + +> [sort函数用法详解](https://blog.csdn.net/qq_41785863/article/details/81128146) +> +> [详细解说 STL 排序(Sort)](http://www.cppblog.com/mzty/archive/2005/12/15/1770.aspx) + +用于C++中,对给定区间所有元素进行排序。头文件是#include + +sort函数进行快速排序,时间复杂度为n*log2n,比冒泡之类的要省时不少 + +Sort函数使用模板: + +Sort(start,end,排序方法) + +1.第一个参数是要排序数组的起始地址 + +2.第二个参数是数组结束地址的下一位 + +3.第三个是排序的方法,可不填,默认升序 + +如果你需要自己定义比较函数,你可以把你定义好的仿函数(functor)作为参数传入。每种算法都支持传入比较函数。以下是所有STL sort算法函数的名字列表: + +| [函数名](http://www.stlchina.org/twiki/bin/view.pl/Main/STLSortAlgorithms?sortcol=0&table=1&up=0#sorted_table) | [功能描述](http://www.stlchina.org/twiki/bin/view.pl/Main/STLSortAlgorithms?sortcol=1&table=1&up=0#sorted_table) | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| sort | 对给定区间所有元素进行排序 | +| stable_sort | 对给定区间所有元素进行稳定排序 | +| partial_sort | 对给定区间所有元素部分排序 | +| partial_sort_copy | 对给定区间复制并排序 | +| nth_element | 找出给定区间的某个位置对应的元素 | +| is_sorted | 判断一个区间是否已经排好序 | +| partition | 使得符合某个条件的元素放在前面 | +| stable_partition | 相对稳定的使得符合某个条件的元素放在前面 | + +其中nth_element 是最不易理解的,实际上,这个函数是用来找出第几个。例如:找出包含7个元素的数组中排在中间那个数的值,此时,我可能不关心前面,也不关心后面,我只关心排在第四位的元素值是多少。 + + + +#### 1.2 sort 中的比较函数 + +当你需要按照某种特定方式进行排序时,你需要给sort指定比较函数,否则程序会自动提供给你一个比较函数。 + +``` +vector < int > vect; +//... +sort(vect.begin(), vect.end()); +//此时相当于调用 +sort(vect.begin(), vect.end(), less() ); + +``` + +上述例子中系统自己为sort提供了less仿函数。在STL中还提供了其他仿函数,以下是仿函数列表: + +| [名称](http://www.stlchina.org/twiki/bin/view.pl/Main/STLSortAlgorithms?sortcol=0&table=2&up=0#sorted_table) | [功能描述](http://www.stlchina.org/twiki/bin/view.pl/Main/STLSortAlgorithms?sortcol=1&table=2&up=0#sorted_table) | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| equal_to | 相等 | +| not_equal_to | 不相等 | +| less | 小于 | +| greater | 大于 | +| less_equal | 小于等于 | +| greater_equal | 大于等于 | + +需要注意的是,这些函数不是都能适用于你的sort算法,如何选择,决定于你的应用。另外,不能直接写入仿函数的名字,而是要写其重载的()函数: + +``` +less() +greater() +``` + +当你的容器中元素时一些标准类型(int float char)或者string时,你可以直接使用这些函数模板。但如果你时自己定义的类型或者你需要按照其他方式排序,你可以有两种方法来达到效果:一种是自己写比较函数。另一种是重载类型的'<'操作赋 + +### 在类的成员函数使用带谓词的sort()函数 + +> [在类的成员函数使用带谓词的sort()函数](https://blog.csdn.net/qf1028622561/article/details/75150998) + +sort()函数接受二元谓词,但是在类内定义的myCompare函数作为成员函数,实际上有三个参数,this指针、m、n。 +解决方案: +1、将myCompare()函数挪到类定义的外面,即改为非成员函数; +2、将myCompare()函数定义为静态成员函数,没有this指针。 + +3、将myCompare()函数定义为类的友元函数,但是此时必须在类外声明该函数,否则,即使在类内定义了该友元函数,该函数仍然是不可见的。 + +### to_string + +按照C++11的标准,to_string函数对每个基础算术类型均有重载函数 + +这个函数也可以自己写 + +```c++ +template +string ToString(const T& t) +{ + + ostringstream oss; // 创建一个流 + + oss < numbers) { + string res=""; + int length=numbers.size(); + if(length<=0) + return res; + vector temp(length); + for(int i=0;i numbers) { + string res=""; + int length=numbers.size(); + if(length<=0) + return res; + vector temp(length); + for(int i=0;i dp(n+1, 1); + dp[n-1] = 1; + for(int i=n-2;i>=0;i--){ + dp[i] = dp[i+1]; + if(s[i]=='1' || (s[i]=='2' && s[i+1]<'6')){ + dp[i] += dp[i+2]; + } + } + return dp[0]; + } +}; +``` + +优化到O(1)空间复杂度 + +```c++ +class Solution { +public: + int getTranslationCount(string s) { + int n=s.size(); + if(n<=0) + return 0; + int res=1,f1=1,f2=1; + for(int i=n-2;i>=0;i--){ + res = f1; + if(s[i]=='1' || (s[i]=='2' && s[i+1]<'6')){ + res+=f2; + } + + f2=f1; + f1=res; + + } + return res; + } +}; + + +``` + + + +## 代码 + +### [c++代码](./src/cpp/046-把数字翻译成字符串.cpp) + +```c++ +class Solution { +public: + int getTranslationCount(string s) { + int n = s.size(); + if(!n) return 0; + if(n==1) return 1; + + vector dp(n+1, 1); + dp[n-1] = 1; + for(int i=n-2;i>=0;i--){ + dp[i] = dp[i+1]; + if(s[i]=='1' || (s[i]=='2' && s[i+1]<'6')){ + dp[i] += dp[i+2]; + } + } + return dp[0]; + } +}; +``` + +### [python代码](./src/python/046-把数字翻译成字符串.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262/src/cpp/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.cpp" "b/\345\211\221\346\214\207offer/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262/src/cpp/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.cpp" new file mode 100644 index 0000000..daed920 --- /dev/null +++ "b/\345\211\221\346\214\207offer/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262/src/cpp/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.cpp" @@ -0,0 +1,18 @@ +class Solution { +public: + int getTranslationCount(string s) { + int n = s.size(); + if(!n) return 0; + if(n==1) return 1; + + vector dp(n+1, 1); + dp[n-1] = 1; + for(int i=n-2;i>=0;i--){ + dp[i] = dp[i+1]; + if(s[i]=='1' || (s[i]=='2' && s[i+1]<'6')){ + dp[i] += dp[i+2]; + } + } + return dp[0]; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262/src/python/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.py" "b/\345\211\221\346\214\207offer/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262/src/python/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262/src/python/046-\346\212\212\346\225\260\345\255\227\347\277\273\350\257\221\346\210\220\345\255\227\347\254\246\344\270\262.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118262231.png" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118262231.png" new file mode 100644 index 0000000..77cef93 Binary files /dev/null and "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118262231.png" differ diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118272502.png" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118272502.png" new file mode 100644 index 0000000..6da4dfa Binary files /dev/null and "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118272502.png" differ diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118289653.png" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118289653.png" new file mode 100644 index 0000000..f725f9f Binary files /dev/null and "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118289653.png" differ diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118302134.png" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118302134.png" new file mode 100644 index 0000000..8333447 Binary files /dev/null and "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/img/readme.assets/1563118302134.png" differ diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/readme.md" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/readme.md" new file mode 100644 index 0000000..9d2c140 --- /dev/null +++ "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/readme.md" @@ -0,0 +1,83 @@ +# 047-礼物的最大价值 + +tags: 动态规划 + +--- + +## 题目原文 + +[acwing链接](https://www.acwing.com/problem/content/56/) + +在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。 + +你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格直到到达棋盘的右下角。 + +给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物? + +**注意:** + +- m,n>0m,n>0 + +样例: + +``` +输入: +[ + [2,3,1], + [1,7,1], + [4,6,1] +] + +输出:19 + +解释:沿着路径 2→3→7→6→1 可以得到拿到最大价值礼物。 +``` + +## 解题思路 + +### 二维数组作为辅助空间 + +![1563118262231](img/readme.assets/1563118262231.png) + +![1563118272502](img/readme.assets/1563118272502.png) + +### 一维数组作为辅助空间 + +![1563118289653](img/readme.assets/1563118289653.png) + +![1563118302134](img/readme.assets/1563118302134.png) + +## 代码 + +### [c++代码](./src/cpp/047-礼物的最大价值.cpp) + +```c++ +class Solution { +public: + int getMaxValue(vector>& grid) { + if(grid.empty()||grid[0].empty()) + return 0; + int rows=grid.size(); + int cols=grid[0].size(); + + vector res(cols); + for(int i=0;i0) + up=res[j]; + if(j>0) + left=res[j-1]; + res[j]=max(up,left)+grid[i][j]; + } + } + return res[cols-1]; + } +}; +``` + +### [python代码](./src/python/047-礼物的最大价值.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/src/cpp/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.cpp" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/src/cpp/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.cpp" new file mode 100644 index 0000000..20d5ced --- /dev/null +++ "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/src/cpp/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.cpp" @@ -0,0 +1,22 @@ +class Solution { +public: + int getMaxValue(vector>& grid) { + if(grid.empty()||grid[0].empty()) + return 0; + int rows=grid.size(); + int cols=grid[0].size(); + + vector res(cols); + for(int i=0;i0) + up=res[j]; + if(j>0) + left=res[j-1]; + res[j]=max(up,left)+grid[i][j]; + } + } + return res[cols-1]; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/src/python/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.py" "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/src/python/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274/src/python/047-\347\244\274\347\211\251\347\232\204\346\234\200\345\244\247\344\273\267\345\200\274.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156526763.png" "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156526763.png" new file mode 100644 index 0000000..d9b4af1 Binary files /dev/null and "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156526763.png" differ diff --git "a/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156538752.png" "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156538752.png" new file mode 100644 index 0000000..f4b4730 Binary files /dev/null and "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156538752.png" differ diff --git "a/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156548398.png" "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156548398.png" new file mode 100644 index 0000000..fa79c58 Binary files /dev/null and "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/img/readme.assets/1563156548398.png" differ diff --git "a/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/readme.md" "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/readme.md" new file mode 100644 index 0000000..3820ef0 --- /dev/null +++ "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/readme.md" @@ -0,0 +1,63 @@ +# 048-最长不含重复字符的子字符串 + +tags: 动态规划 + +--- + +## 题目原文 + +[acwing链接](https://www.acwing.com/problem/content/57/) + +请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 + +假设字符串中只包含从’a’到’z’的字符。 + +## 解题思路 + +![1563156526763](img/readme.assets/1563156526763.png) + +![1563156538752](img/readme.assets/1563156538752.png) + +![1563156548398](img/readme.assets/1563156548398.png) + +## 代码 + +### [c++代码](./src/cpp/048-最长不含重复字符的子字符串.cpp) + +```c++ +class Solution { +public: + int longestSubstringWithoutDuplication(string s) { + if(s.empty()) + return 0; + + int curLength=0; + int maxLength=0; + + vector pos(26,-1); + + for(int i=0;icurLength) + curLength++; + else{ + if(curLength>maxLength) + maxLength=curLength; + + curLength=i-pre_pos; + } + pos[s[i]-'a']=i; + } + if(curLength>maxLength) + maxLength=curLength; + return maxLength; + + } +}; +``` + +### [python代码](./src/python/048-最长不含重复字符的子字符串.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/src/cpp/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.cpp" "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/src/cpp/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.cpp" new file mode 100644 index 0000000..972afdb --- /dev/null +++ "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/src/cpp/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.cpp" @@ -0,0 +1,29 @@ +class Solution { +public: + int longestSubstringWithoutDuplication(string s) { + if(s.empty()) + return 0; + + int curLength=0; + int maxLength=0; + + vector pos(26,-1); + + for(int i=0;icurLength) + curLength++; + else{ + if(curLength>maxLength) + maxLength=curLength; + + curLength=i-pre_pos; + } + pos[s[i]-'a']=i; + } + if(curLength>maxLength) + maxLength=curLength; + return maxLength; + + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/src/python/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.py" "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/src/python/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262/src/python/048-\346\234\200\351\225\277\344\270\215\345\220\253\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\345\255\220\345\255\227\347\254\246\344\270\262.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/049-\344\270\221\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/049-\344\270\221\346\225\260/readme.md" new file mode 100644 index 0000000..a8688d1 --- /dev/null +++ "b/\345\211\221\346\214\207offer/049-\344\270\221\346\225\260/readme.md" @@ -0,0 +1,136 @@ +# 049-丑数 + +tags:空间换时间 + +--- + +## 题目原文 + +[牛客网链接]() + + + +## 解题思路 + +[参考]([https://github.com/gatieme/CodingInterviews/tree/master/034-%E4%B8%91%E6%95%B0](https://github.com/gatieme/CodingInterviews/tree/master/034-丑数)) + +### 暴力方法 + +最简单直接的方法,就是**逐个判断每个整数是不是丑数**,循环所有数字,判断它是不是丑数 首先我们需要判断某个整数number是不是丑数 + +``` +bool IsUglyNumber(int number) +{ + while(number % 5 == 0) + { + number /= 5; + } + + while(number % 3 == 0) + { + number /= 3; + } + + while(number % 2 == 0) + { + number /= 2; + } + + return (number == 1); +} +``` + +然后接下来,就是按照顺序判断每一个整数是不是丑数 + +``` +int GetUglyNumber_Solution(int index) +{ + if(index <= 0) + { + return -1; + } + + int count = 1; + int num = 0; + + while(count <= index) + { + num++; + if(IsUglyNumber(num) == 1) + { + debug <<"count = "< ugly(index); + ugly[0]=1; + int idx2=0,idx3=0,idx5=0,idx=1,val; + + while(idx ugly(index); + ugly[0]=1; + int idx2=0,idx3=0,idx5=0,idx=1,val; + + while(idx ugly(index); + ugly[0]=1; + int idx2=0,idx3=0,idx5=0,idx=1,val; + + while(idx [关于有符号数和无符号数的转换 - C/C++](https://www.cnblogs.com/lakeone/p/4985373.html) +> +> [char, unsigned char, int,unsigned int之间的相互转换](https://blog.csdn.net/WZJwzj123456/article/details/84679383) + +无符号整数和有符号整数之间进行强制类型转换时,位模式不改变。 + +有符号数转换为无符号数时,负数转换为大的正数,相当于在原值上加上2的n次方,而正数保持不变。 + +无符号数转换为有符号数时,对于小的数将保持原值,对于大的数将转换为负数,相当于原值减去2的n次方。 + +当表达式中存在有符号数和无符号数类型时,所有的操作都自动转换为无符号类型。可见无符号数的运算优先级高于有符号数。 + +``` +unsigned int a = 20; +signed int b = -130; +``` + + 运算一下结果是 b>a 。 + +## 代码 + +### [c++代码](./src/cpp/050_01-第一个只出现一次的字符.cpp) + +```c++ +class Solution { +public: + int FirstNotRepeatingChar(string str) { + if(str.empty()) + return -1; + unsigned int hashTable[256]={0}; + int i=0; + for(;i [C++ - 内置类型的最大值宏定义](https://blog.csdn.net/caroline_wendy/article/details/24311895) + +## 代码 + +### [c++代码](./src/cpp/050_02-字符流中第一个只出现一次的字符.cpp) + +```c++ +class Solution{ +public: + //Insert one char from stringstream + Solution():index(0){ + for(int i=0;i<256;i++) + occurrence[i]=-1; + } + + void insert(char ch) + { + if(occurrence[ch] == -1) + occurrence[ch] = index; + else if(occurrence[ch] >= 0) + occurrence[ch] = -2; + + index++; + } + + char firstAppearingOnce() + { + char ch; + int minIndex = INT_MAX; + for(int i = 0; i < 256; ++i) + { + if(occurrence[i] >= 0 && occurrence[i] < minIndex) + { + ch = (char) i; + minIndex = occurrence[i]; + } + } + if(minIndex == INT_MAX) + return '#'; + else + return ch; + } +private: + int index; + // occurrence[i]: A character with ASCII value i; + // occurrence[i] = -1: The character has not found; + // occurrence[i] = -2: The character has been found for mutlple times + // occurrence[i] >= 0: The character has been found only once + int occurrence[256]; +}; +``` + +### [python代码](./src/python/050_02-字符流中第一个只出现一次的字符.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246/src/cpp/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.cpp" "b/\345\211\221\346\214\207offer/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246/src/cpp/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.cpp" new file mode 100644 index 0000000..148b6a1 --- /dev/null +++ "b/\345\211\221\346\214\207offer/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246/src/cpp/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.cpp" @@ -0,0 +1,43 @@ +class Solution{ +public: + //Insert one char from stringstream + Solution():index(0){ + for(int i=0;i<256;i++) + occurrence[i]=-1; + } + + void insert(char ch) + { + if(occurrence[ch] == -1) + occurrence[ch] = index; + else if(occurrence[ch] >= 0) + occurrence[ch] = -2; + + index++; + } + + char firstAppearingOnce() + { + char ch; + int minIndex = INT_MAX; + for(int i = 0; i < 256; ++i) + { + if(occurrence[i] >= 0 && occurrence[i] < minIndex) + { + ch = (char) i; + minIndex = occurrence[i]; + } + } + if(minIndex == INT_MAX) + return '#'; + else + return ch; + } +private: + int index; + // occurrence[i]: A character with ASCII value i; + // occurrence[i] = -1: The character has not found; + // occurrence[i] = -2: The character has been found for mutlple times + // occurrence[i] >= 0: The character has been found only once + int occurrence[256]; +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246/src/python/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.py" "b/\345\211\221\346\214\207offer/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246/src/python/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246/src/python/050_02-\345\255\227\347\254\246\346\265\201\344\270\255\347\254\254\344\270\200\344\270\252\345\217\252\345\207\272\347\216\260\344\270\200\346\254\241\347\232\204\345\255\227\347\254\246.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218163120151-452283750.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218163120151-452283750.png" new file mode 100644 index 0000000..99ca023 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218163120151-452283750.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218194508761-468169540.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218194508761-468169540.png" new file mode 100644 index 0000000..306c861 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218194508761-468169540.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218194621308-588010220.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218194621308-588010220.png" new file mode 100644 index 0000000..51eff79 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1024555-20161218194621308-588010220.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185851304.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185851304.png" new file mode 100644 index 0000000..16003cb Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185851304.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185869762.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185869762.png" new file mode 100644 index 0000000..69c6e16 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185869762.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185881906.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185881906.png" new file mode 100644 index 0000000..6200f1d Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185881906.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185892384.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185892384.png" new file mode 100644 index 0000000..f9a53f7 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563185892384.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188181777.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188181777.png" new file mode 100644 index 0000000..7a8f76e Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188181777.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188264832.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188264832.png" new file mode 100644 index 0000000..c3115e5 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188264832.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188625313.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188625313.png" new file mode 100644 index 0000000..19e9b86 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188625313.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188841314.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188841314.png" new file mode 100644 index 0000000..614eda7 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188841314.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188849537.png" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188849537.png" new file mode 100644 index 0000000..16fbcd6 Binary files /dev/null and "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/img/readme.assets/1563188849537.png" differ diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/readme.md" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/readme.md" new file mode 100644 index 0000000..e104d0a --- /dev/null +++ "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/readme.md" @@ -0,0 +1,253 @@ +# 051-数组中的逆序对 + +tags: 归并排序 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5?tpId=13&tqId=11188&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007 + +**输入描述:** + +``` +题目保证输入的数组中没有的相同的数字数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5 +``` + +示例1 + +输入 + +``` +1,2,3,4,5,6,7,0 +``` + +输出 + +``` +7 +``` + +## 解题思路 + +### 冒泡排序 + +考虑一下,逆序是说a[i]>a[j],i elem) + { + if(elem.size( ) == 0) + { + return 0; + } + + return BubbleSort(elem)%1000000007; + } + + long BubbleSort(vector elem) + { + bool flag = true; + int count = 0; + unsigned int length = elem.size( ); + + for(unsigned int i = 0; + i < length - 1 && flag == true; + i++) // 共计进行length-1趟循环 + { + flag = false; // 初始默认数据是无序的 + for(unsigned int j = 0; + j < length - i - 1; + j++) // 每趟循环比较length-1-j次 + { + if(elem[j] > elem[j + 1]) // 如果当前的元素与后一个元素不满足排序规则 + { + swap(elem[j], elem[j+1]); + flag = true; // 仍然需要交换说明, 仍然无序 + count++; + } + } + } + + return count; + } +}; +``` + + + +### 归并排序 + +![1563185851304](img/readme.assets/1563185851304.png) + +![1563185869762](img/readme.assets/1563185869762.png) + +![1563185881906](img/readme.assets/1563185881906.png) + +![1563185892384](img/readme.assets/1563185892384.png) + +```c++ +class Solution { +public: + int InversePairs(vector data) { + if(data.empty()) + return 0; + //排序的辅助数组 + int length=data.size(); + vector copy(length); + for(int i=0;i& data, vector©,int begin,int end){ + if(begin==end){ + copy[begin]=data[end]; + return 0; + } + // 求中点 + int mid=(begin+end)>>1; + // 使data左半段有序,并返回左半段逆序对的数目 + long leftCount=InversePairsCore(copy,data,begin,mid); + // 使data右半段有序,并返回右半段逆序对的数目 + long rightCount=InversePairsCore(copy,data,mid+1,end); + + int i=mid;// i初始化为前半段最后一个数字的下标 + int j=end;// j初始化为后半段最后一个数字的下标 + int idx_copy=end;// 辅助数组复制的数组的最后一个数字的下标 + long count=0;// 计数,逆序对的个数,注意类型 + + while(i>=begin&&j>=mid+1){ + if(data[i]>data[j]){ + copy[idx_copy--]=data[i--]; + count+=j-mid; + } + else{ + copy[idx_copy--]=data[j--]; + } + } + for(;i>=begin;i--) + copy[idx_copy--]=data[i]; + for(;j>=mid+1;j--) + copy[idx_copy--]=data[j]; + return leftCount+rightCount+count; + } +}; +``` + + + +#### 注意 + +代码中InversePairsCore形参的顺序是(data,copy),而递归调用时实参是(copy,data)。 + +这里调换二者顺序的原因解释如下 + +InversePairsCore函数可以如此理解, 它是对data的左右半段进行合并,复制到辅助数组copy中有序。 + +在下图中, 把data合并,复制到copy中, + +![1563188181777](img/readme.assets/1563188181777.png) + +在递归返回时, 也是要 把data合并,复制到copy中. 但是下图中的data却是上图中的copy. 所以在递归调用时, 要为(copy,data) + +![1563188264832](img/readme.assets/1563188264832.png) + +## 归并排序 + +![1563188841314](img/readme.assets/1563188841314.png) + +![1563188849537](img/readme.assets/1563188849537.png) + +[参考](https://www.cnblogs.com/chengxiao/p/6194356.html) + +### 基本思想 + +  归并排序(MERGE-SORT)是利用**归并**的思想实现的排序方法,该算法采用经典的**分治**(divide-and-conquer)策略(分治法将问题**分**(divide)成一些小的问题然后递归求解,而**治(conquer)**的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。 + +**分而治之** + +![img](img/readme.assets/1024555-20161218163120151-452283750.png) + +   可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。**分**阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。 + +### 合并相邻有序子序列 + +  再来看看**治**阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。 + +![img](img/readme.assets/1024555-20161218194508761-468169540.png) + +![img](img/readme.assets/1024555-20161218194621308-588010220.png) + +## 代码 + +### [c++代码](./src/cpp/051-数组中的逆序对.cpp) + +几个易错点 + +- InversePairsCore递归调用和函数定义的data和copy顺序是反的 +- leftCount,rightCount, count要为long +- InversePairsCore函数定义中data和copy要为引用 + +```c++ +class Solution { +public: + int InversePairs(vector data) { + if(data.empty()) + return 0; + //排序的辅助数组 + int length=data.size(); + vector copy(length); + for(int i=0;i& data, vector©,int begin,int end){ + if(begin==end){ + copy[begin]=data[end]; + return 0; + } + // 求中点 + int mid=(begin+end)>>1; + // 使data左半段有序,并返回左半段逆序对的数目 + long leftCount=InversePairsCore(copy,data,begin,mid); + // 使data右半段有序,并返回右半段逆序对的数目 + long rightCount=InversePairsCore(copy,data,mid+1,end); + + int i=mid;// i初始化为前半段最后一个数字的下标 + int j=end;// j初始化为后半段最后一个数字的下标 + int idx_copy=end;// 辅助数组复制的数组的最后一个数字的下标 + long count=0;// 计数,逆序对的个数,注意类型 + + while(i>=begin&&j>=mid+1){ + if(data[i]>data[j]){ + copy[idx_copy--]=data[i--]; + count+=j-mid; + } + else{ + copy[idx_copy--]=data[j--]; + } + } + for(;i>=begin;i--) + copy[idx_copy--]=data[i]; + for(;j>=mid+1;j--) + copy[idx_copy--]=data[j]; + return leftCount+rightCount+count; + } +}; +``` + +### [python代码](./src/python/051-数组中的逆序对.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/src/cpp/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.cpp" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/src/cpp/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.cpp" new file mode 100644 index 0000000..e69de29 diff --git "a/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/src/python/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/src/python/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271/src/python/051-\346\225\260\347\273\204\344\270\255\347\232\204\351\200\206\345\272\217\345\257\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/img/readme.assets/1563199311027.png" "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/img/readme.assets/1563199311027.png" new file mode 100644 index 0000000..1c5e7bd Binary files /dev/null and "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/img/readme.assets/1563199311027.png" differ diff --git "a/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/img/readme.assets/1563199323151.png" "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/img/readme.assets/1563199323151.png" new file mode 100644 index 0000000..c23a3d7 Binary files /dev/null and "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/img/readme.assets/1563199323151.png" differ diff --git "a/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/readme.md" "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/readme.md" new file mode 100644 index 0000000..01ba49e --- /dev/null +++ "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/readme.md" @@ -0,0 +1,75 @@ +# 052-两个链表的第一个公共结点 + +tags: 链表 两指针 + +--- + +## 题目原文 + +[牛客网链接](https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tpId=13&tqId=11189&tPage=2&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) + +输入两个链表,找出它们的第一个公共结点。 + +## 解题思路 + +![1563199311027](img/readme.assets/1563199311027.png) + +![1563199323151](img/readme.assets/1563199323151.png) + +## 代码 + +### [c++代码](./src/cpp/052-两个链表的第一个公共结点.cpp) + +```c++ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +};*/ +class Solution { +public: + ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { + if(pHead1==nullptr||pHead2==nullptr) + return nullptr; + int listLength1=GetListLength(pHead1); + int listLength2=GetListLength(pHead2); + ListNode* longListNode=pHead1; + ListNode* shortListNode=pHead2; + int difLength=listLength1-listLength2; + if(listLength1next; + } + + while(longListNode!=nullptr&&shortListNode!=nullptr&&longListNode->val!=shortListNode->val){ + longListNode=longListNode->next; + shortListNode=shortListNode->next; + } + return longListNode; + } + int GetListLength(ListNode* pHead){ + if(pHead==nullptr) + return 0; + int length=1; + while(pHead->next!=nullptr){ + pHead=pHead->next; + length++; + } + return length; + } +}; +``` + +### [python代码](./src/python/052-两个链表的第一个公共结点.py) + +```python + +``` diff --git "a/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/src/cpp/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271.cpp" "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/src/cpp/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271.cpp" new file mode 100644 index 0000000..4062020 --- /dev/null +++ "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/src/cpp/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271.cpp" @@ -0,0 +1,45 @@ +/* +struct ListNode { + int val; + struct ListNode *next; + ListNode(int x) : + val(x), next(NULL) { + } +};*/ +class Solution { +public: + ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { + if(pHead1==nullptr||pHead2==nullptr) + return nullptr; + int listLength1=GetListLength(pHead1); + int listLength2=GetListLength(pHead2); + ListNode* longListNode=pHead1; + ListNode* shortListNode=pHead2; + int difLength=listLength1-listLength2; + if(listLength1next; + } + + while(longListNode!=nullptr&&shortListNode!=nullptr&&longListNode->val!=shortListNode->val){ + longListNode=longListNode->next; + shortListNode=shortListNode->next; + } + return longListNode; + } + int GetListLength(ListNode* pHead){ + if(pHead==nullptr) + return 0; + int length=1; + while(pHead->next!=nullptr){ + pHead=pHead->next; + length++; + } + return length; + } +}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/src/python/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271.py" "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/src/python/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271.py" new file mode 100644 index 0000000..380474e --- /dev/null +++ "b/\345\211\221\346\214\207offer/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271/src/python/052-\344\270\244\344\270\252\351\223\276\350\241\250\347\232\204\347\254\254\344\270\200\344\270\252\345\205\254\345\205\261\347\273\223\347\202\271.py" @@ -0,0 +1 @@ +# -*- coding:utf-8 -*- diff --git "a/\345\211\221\346\214\207offer/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/cpp/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.cpp" "b/\345\211\221\346\214\207offer/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/cpp/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.cpp" deleted file mode 100644 index eb04817..0000000 --- "a/\345\211\221\346\214\207offer/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276/src/cpp/\344\272\214\347\273\264\346\225\260\347\273\204\344\270\255\347\232\204\346\237\245\346\211\276.cpp" +++ /dev/null @@ -1,15 +0,0 @@ -class Solution { -public: - bool Find(int target, vector > array) { - bool find=false; - for(int row=0,col=array[row].size()-1;row < array.size()&&col>=0;){ - if (target==array[row][col]) - return find=true; - else if(array[row][col]>target) - col--; - else - row++; - } - return find; - } -}; \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/readme.md" "b/\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/readme.md" deleted file mode 100644 index 19fa154..0000000 --- "a/\345\211\221\346\214\207offer/\344\272\214\350\277\233\345\210\266\344\270\2551\347\232\204\344\270\252\346\225\260/readme.md" +++ /dev/null @@ -1,118 +0,0 @@ -#递归 二进制中1的个数 - -tags: 位运算 - ---- - -## 题目原文 -大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。 -n<=39 - -## 解题思路 -### 低效率不实用的方法 -斐波那契数列的求解方法最容易些想到的就是如下的递归形式 -```c++ -long long Fibonacci(unsigned int n){ - if (n<=0) - return 0; - - if (n==1) - return 1; - - return Fibonacci(n-1)+Fibonacci(n-2) -} -``` -上面的递归形式看起来很简单,但效率却很低,因为在递归的过程中存在着大量的重复计算。例如,计算f(10)的时候需要计算f(8)和f(9),在计算f(9)的时候又要计算一遍f(8),因此,计算的时间复杂度会随着n的增大而指数级增大。 - -### 改进方法 - -上面的方法问题在于递归的过程存在大量的重复计算,因此可以考虑在计算的过程中把计算结果保存下来,比如建立一个数组保存中间计算结果,但这也不是好的方法,因为耗费了额外的内存空间。 - -换种思路,先根据f(0)和f(1)计算出f(2),再依次计算出f(3),f(4),...,f(n),这种计算方法的空间复杂度是常数,时间复杂度是$\Theta(n)$ - - -### 时间复杂度为$\Theta(logn)$但不是很实用的解法 -介绍解法之前先介绍下面的数学公式: - -$$\begin{bmatrix}f(n)&f(n-1)\\f(n-1)&f(n-2) \end{bmatrix}=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$$ - -这个公式可以用数学归纳法证明,有了这个公示后,原来的问题就变成了求矩阵$=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$,若果只是简单的从0开始循环计算,n次方需要n次计算,时间复杂度仍为$\Theta(n)$,与前面的方法相同,但可以考虑乘方的如下性质 - -$$a^n=\begin{cases} a^{n/2}.a^{n/2} &\text{n为偶数} \\ a^{(n-1)/2}.a^{(n-1)/2}.a & \text{n为奇数} \end{cases}$$ - -但这种方法隐含的时间常数比较大(不是很懂),很少会有软件采用这种算法,另外这种算法实现复杂,有多个递归基,不适合面试。 - -### 拓展 青蛙跳台阶 -题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。 - -通过题目的描述,可以很清晰地看到,这就是一个Fibonacci数列。 - -题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级……也可以跳n级。求总共有多少总跳法,并分析算法的时间复杂度。 - -用f(n)表示青蛙上n级台阶的跳法数,设f(0)=1(f(0)的值代表从起点直接到达终点),所以有 - -f(1)=1 - -f(2)=f(1)+f(0) - -... - -f(n)=f(n-1)+f(n-2)+...+f(n-n)      (a) - -f(n-1)=f(n-2)+f(n-3)+...+f(n-n)      (b) - -(a)减去(b)整理之后得到$f(n)=2f(n-1)$ - -所以有递归公式如下: - -$$f(n)=\begin{cases} 1 &\text{n=0}\\1 & \text{n=1}\\ -2*f(n-1) & \text{n>2}\end{cases}$$ - -### 拓展2 铺瓷砖问题 -我们可以用2x1的小矩形横着或者竖着取覆盖更大的矩阵,请问用8个2x1的小矩形取无重叠地覆盖一个2x8的大矩形,总共有多少种方法? - -![斐波那契数列拓展2][1] -
斐波那契数列拓展2
- -记2x8的覆盖方法记为f(8),用第一个1x2的小矩形取覆大矩形的的最左边时有两个选择,竖着放或者横着放,竖着放的时候,覆盖方法为f(7),横着放的时候,比如在左上角,则左下角也只能在横着放一个小矩形,因此,横着放的时候覆盖方法为f(6),因此f(8)=f(7)+f(6),可以看出这仍然是斐波那契数列。 - - - -## 代码 -### [c++代码](./src/cpp/二进制中1的个数.cpp) - -```c++ -class Solution { -public: - int Fibonacci(int n) { - int result[2]={0,1}; - if (n<2) - return result[n]; - long long int f_zero=0, f_one=1,f_res=0; - int count=1; - while(count= 2: - for i in range(2, n+1): - tempArray[i%2] = tempArray[0] + tempArray[1] - return tempArray[n%2] -``` - -[1]:./img/斐波那契数列拓展2.png \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/readme.md" "b/\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/readme.md" deleted file mode 100644 index 934dde8..0000000 --- "a/\345\211\221\346\214\207offer/\344\273\216\345\260\276\345\210\260\345\244\264\346\211\223\345\215\260\351\223\276\350\241\250/readme.md" +++ /dev/null @@ -1,98 +0,0 @@ -# 链表 从尾到头打印链表 - -tags: 链表 - ---- - -## 题目原文 -题目描述 - - 输入一个链表,从尾到头打印链表每个节点的值。 -输入描述: - - 输入为链表的表头 -输出描述: - - 输出为需要打印的“新链表”的表头 - -## 解题思路 -从头到尾遍历链表,将链表的值依次放入栈中,遍历完成后再依次从栈顶输出每个节点 - -因为递归的本质在于栈就够,因此也可以用递归完成本题。访问一个节点时,先递归输出其子节点,再输出其自身 -## 代码 -### [c++代码](./src/cpp/从尾到头打印链表.cpp) - -```c++ -/** -* struct ListNode { -* int val; -* struct ListNode *next; -* ListNode(int x) : -* val(x), next(NULL) { -* } -* }; -*/ -class Solution { -public: - //使用栈结构的方法 - vector printListFromTailToHead(ListNode* head) { - stack nodes;//由于链表结构简单,用一个辅助变量即可,可以不用栈 - - ListNode *pNode=head; - while(pNode!=NULL){ - nodes.push(pNode); - pNode=pNode->next; - } - //为了效率使用静态vector,使用静态vector后不能使用push_back - vector res(nodes.size()); - int i=0; - while(!nodes.empty()){ - pNode=nodes.top(); - res[i++]=pNode->val; - nodes.pop(); - } - return res; - } - //使用递归的方法 - vector res; - vector printListFromTailToHead2(ListNode* head){ - if(head!=NULL){ - printListFromTailToHead2(head->next); - res.push_back(head->val); - } - return res; - } -}; -``` - -### [python代码](./src/python/从尾到头打印链表.py) - -```python -# -*- coding:utf-8 -*- -# class ListNode: -# def __init__(self, x): -# self.val = x -# self.next = None - -class Solution: - # 返回从尾部到头部的列表值序列,例如[1,2,3] - def printListFromTailToHead2(self, listNode): - # write code here - if not listNode: - return [] - res=[] - head=listNode - while head: - res.insert(0,head.val) - head=head.next - return res - def printListFromTailToHead(self, listNode,res=None): - if res==None: - res=[] - if not listNode: - return [] - else: - self.printListFromTailToHead(listNode.next,res) - res.append(listNode.val) - return res -``` diff --git "a/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" "b/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" deleted file mode 100644 index bc1a893..0000000 Binary files "a/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/img/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\346\213\223\345\261\2252.png" and /dev/null differ diff --git "a/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/readme.md" "b/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/readme.md" deleted file mode 100644 index f14f12d..0000000 --- "a/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/readme.md" +++ /dev/null @@ -1,125 +0,0 @@ -#递归 斐波那契数列 - -tags: 递归 - ---- - -## 题目原文 -大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。 -n<=39 - -## 解题思路 -### 低效率不实用的方法 -斐波那契数列的求解方法最容易些想到的就是如下的递归形式 -```c++ -long long Fibonacci(unsigned int n){ - if (n<=0) - return 0; - - if (n==1) - return 1; - - return Fibonacci(n-1)+Fibonacci(n-2) -} -``` -上面的递归形式看起来很简单,但效率却很低,因为在递归的过程中存在着大量的重复计算。例如,计算f(10)的时候需要计算f(8)和f(9),在计算f(9)的时候又要计算一遍f(8),因此,计算的时间复杂度会随着n的增大而指数级增大。 - -### 改进方法 - -上面的方法问题在于递归的过程存在大量的重复计算,因此可以考虑在计算的过程中把计算结果保存下来,比如建立一个数组保存中间计算结果,但这也不是好的方法,因为耗费了额外的内存空间。 - -换种思路,先根据f(0)和f(1)计算出f(2),再依次计算出f(3),f(4),...,f(n),这种计算方法的空间复杂度是常数,时间复杂度是$\Theta(n)$ - -### 代码 -#### [c++代码](./src/cpp/斐波那契数列.cpp) - -```c++ -class Solution { -public: - int Fibonacci(int n) { - int result[2]={0,1}; - if (n<2) - return result[n]; - long long int f_zero=0, f_one=1,f_res=0; - int count=1; - while(count= 2: - for i in range(2, n+1): - tempArray[i%2] = tempArray[0] + tempArray[1] - return tempArray[n%2] -``` - -### 时间复杂度为$\Theta(logn)$但不是很实用的解法 -介绍解法之前先介绍下面的数学公式: - -$$\begin{bmatrix}f(n)&f(n-1)\\f(n-1)&f(n-2) \end{bmatrix}=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$$ - -这个公式可以用数学归纳法证明,有了这个公示后,原来的问题就变成了求矩阵$=\begin{bmatrix}1&1\\1&0 \end{bmatrix}^{n-1}$,若果只是简单的从0开始循环计算,n次方需要n次计算,时间复杂度仍为$\Theta(n)$,与前面的方法相同,但可以考虑乘方的如下性质 - -$$a^n=\begin{cases} a^{n/2}.a^{n/2} &\text{n为偶数} \\ a^{(n-1)/2}.a^{(n-1)/2}.a & \text{n为奇数} \end{cases}$$ - -但这种方法隐含的时间常数比较大(不是很懂),很少会有软件采用这种算法,另外这种算法实现复杂,有多个递归基,不适合面试。 - - -实现上面的方法时,需要定义一个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算,比较麻烦,可以将递归公式转换一下形式: - - -原理:观察:f(n)=f(n-1)+f(n-2)=2f(n-2)+f(n-3)=3f(n-3)+2f(n-4)=5f(n-4)+3f(n-5)=...=f(k).f(n-k+1)+f(k-1).f(n-k) - -若令n=2k,则有f(2k)=f(k).f(k+1)+f(k-1).f(k)=f(k).(f(k)+f(k-1))+f(k-1).f(k)=f(k)^2+2.f(k).f(k-1) - -若令n=2*k-1,则有f(2k-1) -### 拓展 青蛙跳台阶 -题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。 - -通过题目的描述,可以很清晰地看到,这就是一个Fibonacci数列。 - -题目描述: 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级……也可以跳n级。求总共有多少总跳法,并分析算法的时间复杂度。 - -用f(n)表示青蛙上n级台阶的跳法数,设f(0)=1(f(0)的值代表从起点直接到达终点),所以有 - -f(1)=1 - -f(2)=f(1)+f(0) - -... - -f(n)=f(n-1)+f(n-2)+...+f(n-n)      (a) - -f(n-1)=f(n-2)+f(n-3)+...+f(n-n)      (b) - -(a)减去(b)整理之后得到$f(n)=2f(n-1)$ - -所以有递归公式如下: - -$$f(n)=\begin{cases} 1 &\text{n=0}\\1 & \text{n=1}\\ -2*f(n-1) & \text{n>2}\end{cases}$$ - -### 拓展2 铺瓷砖问题 -我们可以用2x1的小矩形横着或者竖着取覆盖更大的矩阵,请问用8个2x1的小矩形取无重叠地覆盖一个2x8的大矩形,总共有多少种方法? - -![斐波那契数列拓展2][1] -
斐波那契数列拓展2
- -记2x8的覆盖方法记为f(8),用第一个1x2的小矩形取覆大矩形的的最左边时有两个选择,竖着放或者横着放,竖着放的时候,覆盖方法为f(7),横着放的时候,比如在左上角,则左下角也只能在横着放一个小矩形,因此,横着放的时候覆盖方法为f(6),因此f(8)=f(7)+f(6),可以看出这仍然是斐波那契数列。 - - -[1]:./img/斐波那契数列拓展2.png \ No newline at end of file diff --git "a/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/cpp/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.cpp" "b/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/cpp/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.cpp" deleted file mode 100644 index 9cba664..0000000 --- "a/\345\211\221\346\214\207offer/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227/src/cpp/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227.cpp" +++ /dev/null @@ -1,17 +0,0 @@ -class Solution { -public: - int Fibonacci(int n) { - int result[2]={0,1}; - if (n<2) - return result[n]; - long long int f_zero=0, f_one=1,f_res=0; - int count=1; - while(count= 2: - for i in range(2, n+1): - tempArray[i%2] = tempArray[0] + tempArray[1] - return tempArray[n%2] \ No newline at end of file diff --git "a/\347\211\233\345\256\242\347\275\2212017\347\254\224\350\257\225\351\242\230\345\220\210\351\233\206/\345\220\210\345\224\261\345\233\242/readme.md" "b/\347\211\233\345\256\242\347\275\2212017\347\254\224\350\257\225\351\242\230\345\220\210\351\233\206/\345\220\210\345\224\261\345\233\242/readme.md" index 92089d2..48eeeba 100644 --- "a/\347\211\233\345\256\242\347\275\2212017\347\254\224\350\257\225\351\242\230\345\220\210\351\233\206/\345\220\210\345\224\261\345\233\242/readme.md" +++ "b/\347\211\233\345\256\242\347\275\2212017\347\254\224\350\257\225\351\242\230\345\220\210\351\233\206/\345\220\210\345\224\261\345\233\242/readme.md" @@ -21,15 +21,16 @@ tags: 动态规划 输入 3 - + 7 4 7 - + 2 50 输出 49 ## 题目大意 + 有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗? @@ -49,12 +50,38 @@ tags: 动态规划 为了能够编程实现,需要归纳出其递推公式,而在写递推公式之前,首先又需要对其进行数学描述 -记第k个人的位置为one,则可以用f[one][k]表示从n个人中选择k个的方案。然后,它的子问题,需要从one前面的left个人里面,选择k-1个,这里left表示k-1个人中最后一个(即第k-1个)人的位置,因此,子问题可以表示成f[left][k-1]. +记输入数组为arr, 记第k个人的位置为i,则可以用f[k].[i]表示最后一人位置为i的时候, 从中选取k个人的最大的乘积。求解f[k].[i], 可以将其分解为子问题, 即f[k-1].[p]与arr[i]的乘积, 这里arr[i]是指输入数组i处的值, f[k-1].[p]指的是最后一人位置为p的时候从中选取k-1的人的最优解, 根据题目要求, p的位置是有限制的, 相邻元素的位置差不超过d, 所以p的取值范围为i-d<=p<=i-1, 所以枚举上述p范围内的 f[k-1].[p] 与 arr[i] 相乘, 取最大值, 就得到了f[k].[i]. 上面的过程灭有考虑arr元素为负值的情况, 所以需要保存连个数组, 分别是最大值和最小值 + +这里不直接用递归的原因和斐波那契数列相同, 防止重复计算. 保存中间结果为一个表, 从前向后计算, 降低计算量 + +然后,它的子问题,需要从one前面的left个人里面,选择k-1个,这里left表示k-1个人中最后一个(即第k-1个)人的位置,因此,子问题可以表示成f[left].[k-1]. + +这里需要注意的是一定要对fm和fn的值进行初始化为0,否则每次第一次进入到第三个循环时,fm[k], [i]的值都是随机的,得不到正确答案。 + +两个注意点: -这里需要注意的是一定要对fm和fn的值进行初始化为0,否则每次第一次进入到第三个循环时,fm[k][i]的值都是随机的,得不到正确答案。 +- 相邻的两名学生在排列中的编号不能超过d(d由题目输入给出) +- 学生能力值可以为负. +## c++ 知识点 + +long long整型有两种:long long和unsigned long long。在C++11中,标准要求long long整型可以在不同平台上有不同的长度,但至少有64位。我们在写常数字面量时,可以使用LL后缀(或是ll)标识一个long long类型的字面量,而ULL(或ull、Ull、uLL)表示一个unsigned long long类型的字面量。比如: + +long long int lli = -9000000000000000000LL; +unsigned long long int ulli = -9000000000000000000ULL; + +同其他的整型一样,要了解平台上long long大小的方法就是查看(或中的宏)。与long long整型相关的一共有3个:LLONG_MIN、LLONG_MAX和ULLONG_MIN,它们分别代表了平台上最小的long long值、最大的long long值,以及最大的unsigned long long值。 + +## 参考 + +[牛客网编程题——合唱团(网易2017)](https://blog.csdn.net/banana_cjb/article/details/80334127) + +[ 清晰解题: 网易笔试合唱团](https://blog.csdn.net/lengxiao1993/article/details/52305420) + +[《合唱团》算法解析(含思路解答示意图)【牛客网编程题——JAVA实现】](https://blog.csdn.net/lhl1124281072/article/details/79966193) ## 代码 + ### [c++代码](./src/cpp/合唱团.cpp) ```c++ diff --git "a/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/img/\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.assets/v2-5fce1634562e2ec0fbe47dd926e325b3_hd.jpg" "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/img/\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.assets/v2-5fce1634562e2ec0fbe47dd926e325b3_hd.jpg" new file mode 100644 index 0000000..64305b0 Binary files /dev/null and "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/img/\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.assets/v2-5fce1634562e2ec0fbe47dd926e325b3_hd.jpg" differ diff --git "a/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\344\270\255\345\220\216\345\261\202\351\201\215\345\216\206/readme.md" "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\344\270\255\345\220\216\345\261\202\351\201\215\345\216\206/readme.md" new file mode 100644 index 0000000..05469e4 --- /dev/null +++ "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\344\270\255\345\220\216\345\261\202\351\201\215\345\216\206/readme.md" @@ -0,0 +1,7 @@ +# 二叉树的前中后层遍历 + +参考 + +> [【图解数据结构】 二叉树遍历](https://www.cnblogs.com/songwenjie/p/8955856.html) +> +> 邓俊辉的图解数据结构 \ No newline at end of file diff --git "a/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\345\277\253\351\200\237\346\216\222\345\272\217/readme.md" "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\345\277\253\351\200\237\346\216\222\345\272\217/readme.md" index d99593d..fe41c39 100644 --- "a/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\345\277\253\351\200\237\346\216\222\345\272\217/readme.md" +++ "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\345\277\253\351\200\237\346\216\222\345\272\217/readme.md" @@ -13,7 +13,6 @@ tags: 排序 ![快速排序过程示意图-维基][1]
快速排序过程示意图-维基
- ## 快速排序过程 一、划分:本质上快速排序把数据划分成几份,所以快速排序通过选取一个关键数据,再根据它的大小,把原数组分成两个子数组:第一个数组里的数都比这个主元数据小或等于,而另一个数组里的数都比这个主元数据要大或等于。 @@ -54,6 +53,16 @@ $$T(n)=2T(n/2)+\Theta(n)=\Theta(nlgn)$$ ## 代码 ### [c++代码](./src/cpp/快速排序.cpp) +下面的代码是<<剑指offer>>第二版的p80页的实现. Partition函数的功能是在数组中选择一个数字, 将数组分为两部分, 比选择数字小的移到数组的左边, 大于等于选择数字的移到数组的右边.Partition函数中, 循环中的small的作用是标记变量. 进入if语句前,small对应元素为序列已遍历元素中小于data[end]的索引最大元素;small+1后,small对应已遍历元素中大于等于data[end]的索引最小元素.整个if判断的意思就是, 当发现data[index]小于选择的数字时, 就将data[index]与data[small+1] (这里small是++之前的) 对应的对应已遍历元素中大于等于data[end]的索引最小元素进行交换. + +函数RandomInRange用于生成一个在start和end之间的数字. + +Swap的作用是用来交换两个数字 + +程序的思想是用递归的思路对选中的数字的左右两边进行排序. + +对于长度为n的数组排序,只需要把start设为0、把end设为n-1,调用函数QuickSot即可 + ```c++ /** * 快速排序的简单代码示例 diff --git "a/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" new file mode 100644 index 0000000..da50862 --- /dev/null +++ "b/\347\273\217\345\205\270\347\256\227\346\263\225&&\346\225\260\346\215\256\347\273\223\346\236\204/\346\216\222\345\272\217\347\256\227\346\263\225\346\200\273\347\273\223.md" @@ -0,0 +1,9 @@ + + +> [必学十大经典排序算法,看这篇就够了(附完整代码动图优质文章)](https://zhuanlan.zhihu.com/p/57088609) +> +> [数据结构的那些排序算法总是记不住,这个真的背的吗?](https://www.zhihu.com/question/51337272/answer/572455307) +> +> [视频 | 手撕九大经典排序算法,看我就够了!](https://zhuanlan.zhihu.com/p/52884590) + +![img](img/排序算法总结.assets/v2-5fce1634562e2ec0fbe47dd926e325b3_hd.jpg) \ No newline at end of file