diff --git a/problems/0005.最长回文子串.md b/problems/0005.最长回文子串.md index 30851a46..cb022ac3 100644 --- a/problems/0005.最长回文子串.md +++ b/problems/0005.最长回文子串.md @@ -263,6 +263,32 @@ public: ## Java ```java +// 双指针 中心扩散法 +class Solution { + public String longestPalindrome(String s) { + String s1 = ""; + String s2 = ""; + String res = ""; + for (int i = 0; i < s.length(); i++) { + // 分两种情况:即一个元素作为中心点,两个元素作为中心点 + s1 = extend(s, i, i); // 情况1 + res = s1.length() > res.length() ? s1 : res; + s2 = extend(s, i, i + 1); // 情况2 + res = s2.length() > res.length() ? s2 : res; + } + return res; // 返回最长的 + } + public String extend(String s, int start, int end){ + String tmp = ""; + while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){ + tmp = s.substring(start, end + 1); // Java中substring是左闭右开的,所以要+1 + // 向两边扩散 + start--; + end++; + } + return tmp; + } +} ``` ## Python @@ -317,6 +343,7 @@ class Solution: ## Go ```go + ``` ## JavaScript diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index c70d522e..1c654dd4 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -118,7 +118,7 @@ next数组就是一个前缀表(prefix table)。 此时就要问了**前缀表是如何记录的呢?** -首先要知道前缀表的任务是当前位置匹配失败,找到之前已经匹配上的位置,在重新匹配,此也意味着在某个字符失配时,前缀表会告诉你下一步匹配中,模式串应该跳到哪个位置。 +首先要知道前缀表的任务是当前位置匹配失败,找到之前已经匹配上的位置,再重新匹配,此也意味着在某个字符失配时,前缀表会告诉你下一步匹配中,模式串应该跳到哪个位置。 那么什么是前缀表:**记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。** @@ -146,7 +146,7 @@ next数组就是一个前缀表(prefix table)。 # 为什么一定要用前缀表 -这就是前缀表那为啥就能告诉我们 上次匹配的位置,并跳过去呢? +这就是前缀表,那为啥就能告诉我们 上次匹配的位置,并跳过去呢? 回顾一下,刚刚匹配的过程在下标5的地方遇到不匹配,模式串是指向f,如图: KMP精讲1 diff --git a/problems/0031.下一个排列.md b/problems/0031.下一个排列.md index 3db099fe..2dad8b27 100644 --- a/problems/0031.下一个排列.md +++ b/problems/0031.下一个排列.md @@ -163,6 +163,29 @@ class Solution: low += 1 high -= 1 ``` +>上一版本简化版 +'''python +class Solution(object): + def nextPermutation(self, nums: List[int]) -> None: + n = len(nums) + i = n-2 + while i >= 0 and nums[i] >= nums[i+1]: + i -= 1 + + if i > -1: // i==-1,不存在下一个更大的排列 + j = n-1 + while j >= 0 and nums[j] <= nums[i]: + j -= 1 + nums[i], nums[j] = nums[j], nums[i] + + start, end = i+1, n-1 + while start < end: + nums[start], nums[end] = nums[end], nums[start] + start += 1 + end -= 1 + + return nums +''' ## Go diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md index 5caddfaa..3c1577a8 100644 --- a/problems/0042.接雨水.md +++ b/problems/0042.接雨水.md @@ -602,7 +602,48 @@ func trap(height []int) int { } ``` +动态规划解法: + +```go +func trap(height []int) int { + sum:=0 + n:=len(height) + lh:=make([]int,n) + rh:=make([]int,n) + lh[0]=height[0] + rh[n-1]=height[n-1] + for i:=1;i=0;i--{ + rh[i]=max(rh[i+1],height[i]) + } + for i:=1;i0{ + sum+=h + } + } + return sum +} +func max(a,b int)int{ + if a>b{ + return a + } + return b +} +func min(a,b int)int{ + if aleft); + //求出右子树深度 + int right = maxDepth(root->right); + //求出左子树深度和右子树深度的较大值 + int max = left > right ? left : right; + //返回较大值+1(1为当前层数) + return max + 1; +} +``` +二叉树最大深度迭代 +```c +int maxDepth(struct TreeNode* root){ + //若传入根节点为NULL,返回0 + if(!root) + return 0; + + int depth = 0; + //开辟队列空间 + struct TreeNode** queue = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 6000); + int queueFront = 0; + int queueEnd = 0; + + //将根结点入队 + queue[queueEnd++] = root; + + int queueSize; + //求出当前队列中元素个数 + while(queueSize = queueEnd - queueFront) { + int i; + //若当前队列中结点有左右子树,则将它们的左右子树入队 + for(i = 0; i < queueSize; i++) { + struct TreeNode* tempNode = queue[queueFront + i]; + if(tempNode->left) + queue[queueEnd++] = tempNode->left; + if(tempNode->right) + queue[queueEnd++] = tempNode->right; + } + //更新队头下标 + queueFront += queueSize; + //深度+1 + depth++; + } + return depth; +} +``` + -----------------------
diff --git a/problems/0122.买卖股票的最佳时机II(动态规划).md b/problems/0122.买卖股票的最佳时机II(动态规划).md index 7cd6c0ad..e701a821 100644 --- a/problems/0122.买卖股票的最佳时机II(动态规划).md +++ b/problems/0122.买卖股票的最佳时机II(动态规划).md @@ -197,6 +197,33 @@ class Solution: ``` Go: +```go +// 买卖股票的最佳时机Ⅱ 动态规划 +// 时间复杂度O(n) 空间复杂度O(n) +func maxProfit(prices []int) int { + dp := make([][]int, len(prices)) + status := make([]int, len(prices) * 2) + for i := range dp { + dp[i] = status[:2] + status = status[2:] + } + dp[0][0] = -prices[0] + + for i := 1; i < len(prices); i++ { + dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]) + dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]) + } + + return dp[len(prices) - 1][1] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` ```go func maxProfit(prices []int) int { diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index 47a30ab9..9c269978 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -347,7 +347,38 @@ const maxProfit = prices => { }; ``` +Go: +> 版本一: +```go +// 买卖股票的最佳时机III 动态规划 +// 时间复杂度O(n) 空间复杂度O(n) +func maxProfit(prices []int) int { + dp := make([][]int, len(prices)) + status := make([]int, len(prices) * 4) + for i := range dp { + dp[i] = status[:4] + status = status[4:] + } + dp[0][0], dp[0][2] = -prices[0], -prices[0] + + for i := 1; i < len(prices); i++ { + dp[i][0] = max(dp[i - 1][0], -prices[i]) + dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]) + dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] - prices[i]) + dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] + prices[i]) + } + + return dp[len(prices) - 1][3] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` ----------------------- diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index 22a1a141..73861b35 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -273,6 +273,41 @@ class Solution: return dp[2*k] ``` Go: +版本一: +```go +// 买卖股票的最佳时机IV 动态规划 +// 时间复杂度O(kn) 空间复杂度O(kn) +func maxProfit(k int, prices []int) int { + if k == 0 || len(prices) == 0 { + return 0 + } + + dp := make([][]int, len(prices)) + status := make([]int, (2 * k + 1) * len(prices)) + for i := range dp { + dp[i] = status[:2 * k + 1] + status = status[2 * k + 1:] + } + for j := 1; j < 2 * k; j += 2 { + dp[0][j] = -prices[0] + } + + for i := 1; i < len(prices); i++ { + for j := 0; j < 2 * k; j += 2 { + dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]) + dp[i][j + 2] = max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]) + } + } + return dp[len(prices) - 1][2 * k] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` ```go func maxProfit(k int, prices []int) int { diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index 56052b52..2e964dfc 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -447,7 +447,80 @@ var countNodes = function(root) { }; ``` +## C: +递归法 +```c +int countNodes(struct TreeNode* root) { + //若传入结点不存在,返回0 + if(!root) + return 0; + //算出左右子树的结点总数 + int leftCount = countNodes(root->left); + int rightCount = countNodes(root->right); + //返回左右子树结点总数+1 + return leftCount + rightCount + 1; +} +int countNodes(struct TreeNode* root){ + return getNodes(root); +} +``` + +迭代法 +```c +int countNodes(struct TreeNode* root){ + //记录结点总数 + int totalNum = 0; + //开辟栈空间 + struct TreeNode** stack = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 100); + int stackTop = 0; + //如果root结点不为NULL,则将其入栈。若为NULL,则不会进入遍历,返回0 + if(root) + stack[stackTop++] = root; + //若栈中有结点存在,则进行遍历 + while(stackTop) { + //取出栈顶元素 + struct TreeNode* tempNode = stack[--stackTop]; + //结点总数+1 + totalNum++; + //若栈顶结点有左右孩子,将它们入栈 + if(tempNode->left) + stack[stackTop++] = tempNode->left; + if(tempNode->right) + stack[stackTop++] = tempNode->right; + } + return totalNum; +} +``` + +满二叉树 +```c +int countNodes(struct TreeNode* root){ + if(!root) + return 0; + int leftHeight = 0; + int rightHeight = 0; + struct TreeNode* rightNode = root->right; + struct TreeNode* leftNode = root->left; + //求出左子树深度 + while(leftNode) { + leftNode = leftNode->left; + leftHeight++; + } + + //求出右子树深度 + while(rightNode) { + rightNode = rightNode->right; + rightHeight++; + } + //若左右子树深度相同,为满二叉树。结点个数为2^height-1 + if(rightHeight == leftHeight) { + return (2 << leftHeight) - 1; + } + //否则返回左右子树的结点个数+1 + return countNodes(root->right) + countNodes(root->left) + 1; +} +``` -----------------------
diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index 00f0e1c0..12c60c7e 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -563,7 +563,7 @@ var invertTree = function(root) { }; ``` -C: +### C: 递归法 ```c struct TreeNode* invertTree(struct TreeNode* root){ @@ -580,6 +580,7 @@ struct TreeNode* invertTree(struct TreeNode* root){ return root; } ``` + 迭代法:深度优先遍历 ```c struct TreeNode* invertTree(struct TreeNode* root){ diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md index 5a910908..8a8d3a52 100644 --- a/problems/0239.滑动窗口最大值.md +++ b/problems/0239.滑动窗口最大值.md @@ -408,7 +408,7 @@ var maxSlidingWindow = function (nums, k) { // 入队当前元素下标 q.push(i); // 判断当前最大值(即队首元素)是否在窗口中,若不在便将其出队 - while (q[0] <= i - k) { + if (q[0] <= i - k) { q.shift(); } // 当达到窗口大小时便开始向结果中添加数据 diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index e6c6839a..8520e655 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -205,6 +205,40 @@ class Solution: ``` Go: +```go +// 最佳买卖股票时机含冷冻期 动态规划 +// 时间复杂度O(n) 空间复杂度O(n) +func maxProfit(prices []int) int { + n := len(prices) + if n < 2 { + return 0 + } + + dp := make([][]int, n) + status := make([]int, n * 4) + for i := range dp { + dp[i] = status[:4] + status = status[4:] + } + dp[0][0] = -prices[0] + + for i := 1; i < n; i++ { + dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1] - prices[i], dp[i - 1][3] - prices[i])) + dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]) + dp[i][2] = dp[i - 1][0] + prices[i] + dp[i][3] = dp[i - 1][2] + } + + return max(dp[n - 1][1], max(dp[n - 1][2], dp[n - 1][3])) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` Javascript: diff --git a/problems/0463.岛屿的周长.md b/problems/0463.岛屿的周长.md index 65783cc3..39808e0e 100644 --- a/problems/0463.岛屿的周长.md +++ b/problems/0463.岛屿的周长.md @@ -121,6 +121,41 @@ class Solution { ``` Python: +### 解法1: +扫描每个cell,如果当前位置为岛屿 grid[i][j] == 1, 从当前位置判断四边方向,如果边界或者是水域,证明有边界存在,res矩阵的对应cell加一。 + +```python3 +class Solution: + def islandPerimeter(self, grid: List[List[int]]) -> int: + + m = len(grid) + n = len(grid[0]) + + # 创建res二维素组记录答案 + res = [[0] * n for j in range(m)] + + for i in range(m): + for j in range(len(grid[i])): + # 如果当前位置为水域,不做修改或reset res[i][j] = 0 + if grid[i][j] == 0: + res[i][j] = 0 + # 如果当前位置为陆地,往四个方向判断,update res[i][j] + elif grid[i][j] == 1: + if i == 0 or (i > 0 and grid[i-1][j] == 0): + res[i][j] += 1 + if j == 0 or (j >0 and grid[i][j-1] == 0): + res[i][j] += 1 + if i == m-1 or (i < m-1 and grid[i+1][j] == 0): + res[i][j] += 1 + if j == n-1 or (j < n-1 and grid[i][j+1] == 0): + res[i][j] += 1 + + # 最后求和res矩阵,这里其实不一定需要矩阵记录,可以设置一个variable res 记录边长,舍矩阵无非是更加形象而已 + ans = sum([sum(row) for row in res]) + + return ans + +``` Go: diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index 89cc4927..af945aca 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -354,6 +354,35 @@ var constructMaximumBinaryTree = function (nums) { }; ``` +## C +```c +struct TreeNode* traversal(int* nums, int left, int right) { + //若左边界大于右边界,返回NULL + if(left >= right) + return NULL; + + //找出数组中最大数坐标 + int maxIndex = left; + int i; + for(i = left + 1; i < right; i++) { + if(nums[i] > nums[maxIndex]) + maxIndex = i; + } + + //开辟结点 + struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode)); + //将结点的值设为最大数组数组元素 + node->val = nums[maxIndex]; + //递归定义左孩子结点和右孩子结点 + node->left = traversal(nums, left, maxIndex); + node->right = traversal(nums, maxIndex + 1, right); + return node; +} + +struct TreeNode* constructMaximumBinaryTree(int* nums, int numsSize){ + return traversal(nums, 0, numsSize); +} +``` ----------------------- diff --git a/problems/0669.修剪二叉搜索树.md b/problems/0669.修剪二叉搜索树.md index f6ae146a..89096320 100644 --- a/problems/0669.修剪二叉搜索树.md +++ b/problems/0669.修剪二叉搜索树.md @@ -139,7 +139,7 @@ if (root->val < low) { root->left = trimBST(root->left, low, high); ``` -此时节点3的右孩子就变成了节点2,将节点0从二叉树中移除了。 +此时节点3的左孩子就变成了节点2,将节点0从二叉树中移除了。 最后整体代码如下: diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md index b64d91d2..2b3416d4 100644 --- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md +++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md @@ -150,14 +150,16 @@ class Solution: ``` Go: -```Go +```go +// 买卖股票的最佳时机含手续费 动态规划 +// 时间复杂度O(n) 空间复杂度O(n) func maxProfit(prices []int, fee int) int { n := len(prices) dp := make([][2]int, n) dp[0][0] = -prices[0] for i := 1; i < n; i++ { - dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]-fee) - dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i]) + dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee) + dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) } return dp[n-1][1] } diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 91885f8d..66f34978 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -267,6 +267,57 @@ var removeDuplicates = function(s) { }; ``` +C: +方法一:使用栈 +```c +char * removeDuplicates(char * s){ + //求出字符串长度 + int strLength = strlen(s); + //开辟栈空间。栈空间长度应为字符串长度+1(为了存放字符串结束标志'\0') + char* stack = (char*)malloc(sizeof(char) * strLength + 1); + int stackTop = 0; + + int index = 0; + //遍历整个字符串 + while(index < strLength) { + //取出当前index对应字母,之后index+1 + char letter = s[index++]; + //若栈中有元素,且栈顶字母等于当前字母(两字母相邻)。将栈顶元素弹出 + if(stackTop > 0 && letter == stack[stackTop - 1]) + stackTop--; + //否则将字母入栈 + else + stack[stackTop++] = letter; + } + //存放字符串结束标志'\0' + stack[stackTop] = '\0'; + //返回栈本身作为字符串 + return stack; +} +``` +方法二:双指针法 +```c +char * removeDuplicates(char * s){ + //创建快慢指针 + int fast = 0; + int slow = 0; + //求出字符串长度 + int strLength = strlen(s); + //遍历字符串 + while(fast < strLength) { + //将当前slow指向字符改为fast指向字符。fast指针+1 + char letter = s[slow] = s[fast++]; + //若慢指针大于0,且慢指针指向元素等于字符串中前一位元素,删除慢指针指向当前元素 + if(slow > 0 && letter == s[slow - 1]) + slow--; + else + slow++; + } + //在字符串结束加入字符串结束标志'\0' + s[slow] = 0; + return s; +} +``` ----------------------- diff --git a/problems/1365.有多少小于当前数字的数字.md b/problems/1365.有多少小于当前数字的数字.md index a2592957..5e1e875c 100644 --- a/problems/1365.有多少小于当前数字的数字.md +++ b/problems/1365.有多少小于当前数字的数字.md @@ -150,7 +150,35 @@ class Solution: res[i] = hash[num] return res ``` + Go: +```go +func smallerNumbersThanCurrent(nums []int) []int { + // map,key[数组中出现的数] value[比这个数小的个数] + m := make(map[int]int) + // 拷贝一份原始数组 + rawNums := make([]int,len(nums)) + copy(rawNums,nums) + // 将数组排序 + sort.Ints(nums) + // 循环遍历排序后的数组,值为map的key,索引为value + for i,v := range nums { + _,contains := m[v] + if !contains { + m[v] = i + } + + } + // 返回值结果 + result := make([]int,len(nums)) + // 根据原始数组的位置,存放对应的比它小的数 + for i,v := range rawNums { + result[i] = m[v] + } + + return result +} +``` JavaScript: ```javascript