From 45aa719cf0bc90f86e8b408f4b898772f84b5549 Mon Sep 17 00:00:00 2001 From: youngyangyang04 <826123027@qq.com> Date: Wed, 25 Aug 2021 09:42:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=2047~541=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20=E4=BB=A3=E7=A0=81=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0150.逆波兰表达式求值.md | 48 +++---- problems/0225.用队列实现栈.md | 69 ++++++---- problems/0232.用栈实现队列.md | 106 +++++---------- problems/0279.完全平方数.md | 53 +++++++- problems/0300.最长上升子序列.md | 122 +----------------- problems/0344.反转字符串.md | 23 ++-- problems/0349.两个数组的交集.md | 24 +++- problems/0541.反转字符串II.md | 39 +++--- problems/1002.查找常用字符.md | 44 ++++++- ...除字符串中的所有相邻重复项.md | 39 ++++-- 10 files changed, 267 insertions(+), 300 deletions(-) diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 7eb5bc00..bcde7d5b 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -13,7 +13,7 @@ # 150. 逆波兰表达式求值 -[力扣题目链接](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/) +https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ 根据 逆波兰表示法,求表达式的值。 @@ -23,7 +23,7 @@ 整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 - +  示例 1: * 输入: ["2", "1", "+", "3", " * "] @@ -40,13 +40,13 @@ * 输出: 22 * 解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 - = ((10 * (6 / (12 * -11))) + 17) + 5 - = ((10 * (6 / -132)) + 17) + 5 - = ((10 * 0) + 17) + 5 - = (0 + 17) + 5 - = 17 + 5 - = 22 - += ((10 * (6 / (12 * -11))) + 17) + 5 += ((10 * (6 / -132)) + 17) + 5 += ((10 * 0) + 17) + 5 += (0 + 17) + 5 += 17 + 5 += 22 +  逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。 @@ -62,7 +62,7 @@ # 思路 -在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。 +在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)提到了 递归就是用栈来实现的。 所以**栈与递归之间在某种程度上是可以转换的!** 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。 @@ -70,12 +70,12 @@ 但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。 -在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。** +在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中的对对碰游戏是不是就非常像了。** 如动画所示: ![150.逆波兰表达式求值](https://code-thinking.cdn.bcebos.com/gifs/150.逆波兰表达式求值.gif) -相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不错的,只不过本题不要相邻元素做消除了,而是做运算! +相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)是差不错的,只不过本题不要相邻元素做消除了,而是做运算! C++代码如下: @@ -223,17 +223,19 @@ var evalRPN = function(tokens) { python3 ```python -def evalRPN(tokens) -> int: - stack = list() - for i in range(len(tokens)): - if tokens[i] not in ["+", "-", "*", "/"]: - stack.append(tokens[i]) - else: - tmp1 = stack.pop() - tmp2 = stack.pop() - res = eval(tmp2+tokens[i]+tmp1) - stack.append(str(int(res))) - return stack[-1] +class Solution: + def evalRPN(self, tokens: List[str]) -> int: + stack = [] + for item in tokens: + if item not in {"+", "-", "*", "/"}: + stack.append(item) + else: + first_num, second_num = stack.pop(), stack.pop() + stack.append( + int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面 + ) + return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的 + ``` diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index d6386cee..ccf93f1f 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -12,7 +12,7 @@ # 225. 用队列实现栈 -[力扣题目链接](https://leetcode-cn.com/problems/implement-stack-using-queues/) +https://leetcode-cn.com/problems/implement-stack-using-queues/ 使用队列实现栈的下列操作: @@ -34,7 +34,7 @@ 有的同学可能疑惑这种题目有什么实际工程意义,**其实很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!** -刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://programmercarl.com/0232.用栈实现队列.html)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行! +刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://mp.weixin.qq.com/s/Cj6R0qu8rFA7Et9V_ZMjCA)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行! **队列模拟栈,其实一个队列就够了**,那么我们先说一说两个队列来实现栈的思路。 @@ -294,53 +294,66 @@ Python: ```python from collections import deque + class MyStack: + def __init__(self): """ - Initialize your data structure here. + Python普通的Queue或SimpleQueue没有类似于peek的功能 + 也无法用索引访问,在实现top的时候较为困难。 + + 用list可以,但是在使用pop(0)的时候时间复杂度为O(n) + 因此这里使用双向队列,我们保证只执行popleft()和append(),因为deque可以用索引访问,可以实现和peek相似的功能 + + in - 存所有数据 + out - 仅在pop的时候会用到 """ - #使用两个队列来实现 - self.que1 = deque() - self.que2 = deque() + self.queue_in = deque() + self.queue_out = deque() def push(self, x: int) -> None: """ - Push element x onto stack. + 直接append即可 """ - self.que1.append(x) + self.queue_in.append(x) + def pop(self) -> int: """ - Removes the element on top of the stack and returns that element. + 1. 首先确认不空 + 2. 因为队列的特殊性,FIFO,所以我们只有在pop()的时候才会使用queue_out + 3. 先把queue_in中的所有元素(除了最后一个),依次出列放进queue_out + 4. 交换in和out,此时out里只有一个元素 + 5. 把out中的pop出来,即是原队列的最后一个 + + tip:这不能像栈实现队列一样,因为另一个queue也是FIFO,如果执行pop()它不能像 + stack一样从另一个pop(),所以干脆in只用来存数据,pop()的时候两个进行交换 """ - size = len(self.que1) - size -= 1#这里先减一是为了保证最后面的元素 - while size > 0: - size -= 1 - self.que2.append(self.que1.popleft()) + if self.empty(): + return None - - result = self.que1.popleft() - self.que1, self.que2= self.que2, self.que1#将que2和que1交换 que1经过之前的操作应该是空了 - #一定注意不能直接使用que1 = que2 这样que2的改变会影响que1 可以用浅拷贝 - return result + for i in range(len(self.queue_in) - 1): + self.queue_out.append(self.queue_in.popleft()) + + self.queue_in, self.queue_out = self.queue_out, self.queue_in # 交换in和out,这也是为啥in只用来存 + return self.queue_out.popleft() def top(self) -> int: """ - Get the top element. + 1. 首先确认不空 + 2. 我们仅有in会存放数据,所以返回第一个即可 """ - return self.que1[-1] + if self.empty(): + return None + + return self.queue_in[-1] + def empty(self) -> bool: """ - Returns whether the stack is empty. + 因为只有in存了数据,只要判断in是不是有数即可 """ - #print(self.que1) - if len(self.que1) == 0: - return True - else: - return False - + return len(self.queue_in) == 0 ``` diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 0afbac6b..e8bb877e 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -11,7 +11,7 @@ # 232.用栈实现队列 -[力扣题目链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/) +https://leetcode-cn.com/problems/implement-queue-using-stacks/ 使用栈实现队列的下列操作: @@ -129,54 +129,6 @@ public: Java: -使用Stack(堆栈)同名方法: -```java -class MyQueue { - // java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack - Deque stIn; - Deque stOut; - /** Initialize your data structure here. */ - public MyQueue() { - stIn = new ArrayDeque<>(); - stOut = new ArrayDeque<>(); - } - - /** Push element x to the back of queue. */ - public void push(int x) { - stIn.push(x); - } - - /** Removes the element from in front of queue and returns that element. */ - public int pop() { - // 只要 stOut 为空,那么就应该将 stIn 中所有的元素倒腾到 stOut 中 - if (stOut.isEmpty()) { - while (!stIn.isEmpty()) { - stOut.push(stIn.pop()); - } - } - // 再返回 stOut 中的元素 - return stOut.pop(); - } - - /** Get the front element. */ - public int peek() { - // 直接使用已有的pop函数 - int res = this.pop(); - // 因为pop函数弹出了元素res,所以再添加回去 - stOut.push(res); - return res; - } - - /** Returns whether the queue is empty. */ - public boolean empty() { - // 当 stIn 栈为空时,说明没有元素可以倒腾到 stOut 栈了 - // 并且 stOut 栈也为空时,说明没有以前从 stIn 中倒腾到的元素了 - return stIn.isEmpty() && stOut.isEmpty(); - } -} -``` - - ```java class MyQueue { @@ -234,48 +186,60 @@ class MyQueue { Python: ```python -# 使用两个栈实现先进先出的队列 class MyQueue: + def __init__(self): """ - Initialize your data structure here. + in主要负责push,out主要负责pop """ - self.stack1 = list() - self.stack2 = list() + self.stack_in = [] + self.stack_out = [] + def push(self, x: int) -> None: """ - Push element x to the back of queue. + 有新元素进来,就往in里面push """ - # self.stack1用于接受元素 - self.stack1.append(x) + self.stack_in.append(x) + def pop(self) -> int: """ - Removes the element from in front of queue and returns that element. + 1. 检查如果out里面元素,则直接pop + 2. 如果out没有元素,就把in里面的元素(除了第一个)依次pop后装进out里面 + 3. 直接把in剩下的元素pop出来,就是queue头部的 """ - # self.stack2用于弹出元素,如果self.stack2为[],则将self.stack1中元素全部弹出给self.stack2 - if self.stack2 == []: - while self.stack1: - tmp = self.stack1.pop() - self.stack2.append(tmp) - return self.stack2.pop() + if self.empty: + return None + + if self.stack_out: + return self.stack_out.pop() + else: + for i in range(1, len(self.stack_in)): + self.stack_out.append(self.stack_in.pop()) + return self.stack_in.pop() + def peek(self) -> int: """ - Get the front element. + 1. 查out有没有元素,有就把最上面的返回 + 2. 如果out没有元素,就把in最下面的返回 """ - if self.stack2 == []: - while self.stack1: - tmp = self.stack1.pop() - self.stack2.append(tmp) - return self.stack2[-1] + if self.empty: + return None + + if self.stack_out: + return self.stack_out[-1] + else: + return self.stack_in[0] + def empty(self) -> bool: """ - Returns whether the queue is empty. + 只要in或者out有元素,说明队列不为空 """ - return self.stack1 == [] and self.stack2 == [] + return not (self.stack_in or self.stack_out) + ``` diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md index 8a9c291e..3c0f0414 100644 --- a/problems/0279.完全平方数.md +++ b/problems/0279.完全平方数.md @@ -9,7 +9,7 @@ ## 279.完全平方数 -[力扣题目链接](https://leetcode-cn.com/problems/perfect-squares/) +题目地址:https://leetcode-cn.com/problems/perfect-squares/ 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 @@ -36,7 +36,7 @@ **我来把题目翻译一下:完全平方数就是物品(可以无限件使用),凑个正整数n就是背包,问凑满这个背包最少有多少物品?** -感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)就是一样一样的! +感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)就是一样一样的! 动规五部曲分析如下: @@ -70,7 +70,7 @@ dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。 如果求排列数就是外层for遍历背包,内层for循环遍历物品。 -在[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)中我们就深入探讨了这个问题,本题也是一样的,是求最小数! +在[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)中我们就深入探讨了这个问题,本题也是一样的,是求最小数! **所以本题外层for遍历背包,里层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的!** @@ -146,7 +146,7 @@ public: ## 总结 -如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html),今天这道就非常简单了,一样的套路一样的味道。 +如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ),今天这道就非常简单了,一样的套路一样的味道。 但如果没有按照「代码随想录」的题目顺序来做的话,做动态规划或者做背包问题,上来就做这道题,那还是挺难的! @@ -161,6 +161,7 @@ public: Java: ```Java class Solution { + // 版本一,先遍历物品, 再遍历背包 public int numSquares(int n) { int max = Integer.MAX_VALUE; int[] dp = new int[n + 1]; @@ -170,7 +171,9 @@ class Solution { } //当和为0时,组合的个数为0 dp[0] = 0; + // 遍历物品 for (int i = 1; i * i <= n; i++) { + // 遍历背包 for (int j = i * i; j <= n; j++) { if (dp[j - i * i] != max) { dp[j] = Math.min(dp[j], dp[j - i * i] + 1); @@ -180,6 +183,28 @@ class Solution { return dp[n]; } } + +class Solution { + // 版本二, 先遍历背包, 再遍历物品 + public int numSquares(int n) { + int max = Integer.MAX_VALUE; + int[] dp = new int[n + 1]; + // 初始化 + for (int j = 0; j <= n; j++) { + dp[j] = max; + } + // 当和为0时,组合的个数为0 + dp[0] = 0; + // 遍历背包 + for (int j = 1; j <= n; j++) { + // 遍历物品 + for (int i = 1; i * i <= j; i++) { + dp[j] = Math.min(dp[j], dp[j - i * i] + 1); + } + } + return dp[n]; + } +} ``` Python: @@ -187,7 +212,7 @@ Python: ```python3 class Solution: def numSquares(self, n: int) -> int: - '''版本一''' + '''版本一,先遍历背包, 再遍历物品''' # 初始化 nums = [i**2 for i in range(1, n + 1) if i**2 <= n] dp = [10**4]*(n + 1) @@ -201,7 +226,7 @@ class Solution: return dp[n] def numSquares1(self, n: int) -> int: - '''版本二''' + '''版本二, 先遍历物品, 再遍历背包''' # 初始化 nums = [i**2 for i in range(1, n + 1) if i**2 <= n] dp = [10**4]*(n + 1) @@ -217,6 +242,22 @@ class Solution: Python3: ```python class Solution: + '''版本一,先遍历背包, 再遍历物品''' + def numSquares(self, n: int) -> int: + dp = [n] * (n + 1) + dp[0] = 0 + # 遍历背包 + for j in range(1, n+1): + for i in range(1, n): + num = i ** 2 + if num > j: break + # 遍历物品 + if j - num >= 0: + dp[j] = min(dp[j], dp[j - num] + 1) + return dp[n] + +class Solution: + '''版本二, 先遍历物品, 再遍历背包''' def numSquares(self, n: int) -> int: # 初始化 # 组成和的完全平方数的最多个数,就是只用1构成 diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md index b2e942ed..0ac6e784 100644 --- a/problems/0300.最长上升子序列.md +++ b/problems/0300.最长上升子序列.md @@ -8,13 +8,13 @@ ## 300.最长递增子序列 -[力扣题目链接](https://leetcode-cn.com/problems/longest-increasing-subsequence/) +题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/ 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 - +  示例 1: 输入:nums = [10,9,2,5,3,7,101,18] 输出:4 @@ -27,13 +27,12 @@ 示例 3: 输入:nums = [7,7,7,7,7,7,7] 输出:1 - +  提示: * 1 <= nums.length <= 2500 * -10^4 <= nums[i] <= 104 -## 方法一 动态规划 ## 思路 最长上升子序列是动规的经典题目,这里dp[i]是可以根据dp[j] (j < i)推导出来的,那么依然用动规五部曲来分析详细一波: @@ -189,121 +188,6 @@ const lengthOfLIS = (nums) => { return result; }; ``` -*复杂度分析* -- 时间复杂度:O(n^2)。数组 nums 的长度为 n,我们依次用数组中的元素去遍历 dp 数组,而遍历 dp 数组时需要进行 O(n) 次搜索,所以总时间复杂度为 O(n^2)。 -- 空间复杂度:O(n),需要额外使用长度为 n 的 dp 数组。 - - -## 方法二 贪心策略+二分搜索 - -使用贪心策略和二分搜索可以进一步将算法时间复杂度将为O(nlogn)。 - -## 思路 - -为了使得到的子序列尽可能长,我们需要使序列上升得尽可能慢。 - -对于长度为n的数组 nums,我们从0到n-1依次遍历数组中的每个元素nums[i],更新在0到i范围内最长上升子序列的长度len,以及 在0到i范围内,上升子序列的长度为1到len时,对应长度子序列最右端的最小值,将结果保存在list中。实际编码过程中,list长度即为len。 - -## 可行性 -当我们遍历完数组nums中第n-1个元素时,list中保存的是0到n-1范围内最长上升子序列的长度,即为所求。 - -## 算法复杂度分析 -1. list中的元素是单调递增的。可以用反证法来证明:假设对于0<=i=list[j],那么我们可以在list[j]对应的子序列中删除最后j-i个元素得到长度与list[i]相同的子序列,其最右端的值maxlist[len-1],此时,list中子序列长度为1到len的对应的最右端最小值不变,并新增长度为len+1的子序列,最右端的最小值为nums[i],时间复杂度O(1); - - 2. if(nums[i]<=list[len-1]),此时,我们可以在0到len-1范围内找到k,list[k]为>=nums[i]的最小值,由于list单调递增,所以我们可以使用二分搜索在O(logn)的时间复杂度内找到k。 - 1. 对于0<=jnums[i]; - -3. 综上,算法时间复杂度为O(nlogn),空间复杂度为O(n),需要O(n)的空间保存list。 - -代码如下 - -Java -```java -class Solution { - public int lengthOfLIS(int[] nums) { - int n = nums.length; - if(n==0){return 0;} - - List list=new ArrayList<>(); - list.add(nums[0]); - for (int i = 1; i < n; ++i) { - if (nums[i] > list.get(list.size()-1)) { - list.add(nums[i]); - } else { - int k=binarySearch(list,nums[i]); - list.set(k,nums[i]); - } - } - return list.size(); - } - - int binarySearch(Listlist, int num){ - int len=list.size(); - int l=0,r=len-1,ans=len-1; - while(l<=r){ - int mid=l+(r-l)/2; - if(list.get(mid) list[len-1]) { - list[len++]=nums[i]; - } else { - int k=binarySearch(list,len,nums[i]); - list[k]=nums[i]; - } - } - return len; - } - - int binarySearch(int[] list,int len, int num){ - - int l=0,r=len-1,ans=len-1; - while(l<=r){ - int mid=l+(r-l)/2; - if(list[mid] None: -# """ -# Do not return anything, modify s in-place instead. -# """ - # 不需要判别是偶数个还是奇数个序列,因为奇数个的时候,中间那个不需要交换就可 -# for i in range(len(s)//2): -# s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i] -# return s + ``` Go: diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 49fe926b..62abf639 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -14,7 +14,7 @@ ## 349. 两个数组的交集 -[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/) +https://leetcode-cn.com/problems/intersection-of-two-arrays/ 题意:给定两个数组,编写一个函数来计算它们的交集。 @@ -32,7 +32,7 @@ 这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。 -那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html) +那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA) 但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。** @@ -143,6 +143,26 @@ func intersection(nums1 []int, nums2 []int) []int { return res } ``` +```golang +//优化版,利用set,减少count统计 +func intersection(nums1 []int, nums2 []int) []int { + set:=make(map[int]struct{},0) + res:=make([]int,0) + for _,v:=range nums1{ + if _,ok:=set[v];!ok{ + set[v]=struct{}{} + } + } + for _,v:=range nums2{ + //如果存在于上一个数组中,则加入结果集,并清空该set值 + if _,ok:=set[v];ok{ + res=append(res,v) + delete(set, v) + } + } + return res +} +``` javaScript: diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md index 469b5685..02713c65 100644 --- a/problems/0541.反转字符串II.md +++ b/problems/0541.反转字符串II.md @@ -12,7 +12,7 @@ # 541. 反转字符串II -[力扣题目链接](https://leetcode-cn.com/problems/reverse-string-ii/) +https://leetcode-cn.com/problems/reverse-string-ii/ 给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。 @@ -65,7 +65,7 @@ public: }; ``` -那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://programmercarl.com/0344.反转字符串.html)道理是一样的。 +那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)道理是一样的。 下面我实现的reverse函数区间是左闭右闭区间,代码如下: @@ -155,34 +155,27 @@ class Solution { Python: ```python - -class Solution(object): - def reverseStr(self, s, k): +class Solution: + def reverseStr(self, s: str, k: int) -> str: """ - :type s: str - :type k: int - :rtype: str + 1. 使用range(start, end, step)来确定需要调换的初始位置 + 2. 对于字符串s = 'abc',如果使用s[0:999] ===> 'abc'。字符串末尾如果超过最大长度,则会返回至字符串最后一个值,这个特性可以避免一些边界条件的处理。 + 3. 用切片整体替换,而不是一个个替换. """ - from functools import reduce - # turn s into a list - s = list(s) - - # another way to simply use a[::-1], but i feel this is easier to understand - def reverse(s): - left, right = 0, len(s) - 1 + def reverse_substring(text): + left, right = 0, len(text) - 1 while left < right: - s[left], s[right] = s[right], s[left] + text[left], text[right] = text[right], text[left] left += 1 right -= 1 - return s + return text - # make sure we reverse each 2k elements - for i in range(0, len(s), 2*k): - s[i:(i+k)] = reverse(s[i:(i+k)]) - - # combine list into str. - return reduce(lambda a, b: a+b, s) + res = list(s) + + for cur in range(0, len(s), 2 * k): + res[cur: cur + k] = reverse_substring(res[cur: cur + k]) + return ''.join(res) ``` diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index 39151185..a789373b 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -10,7 +10,7 @@ # 1002. 查找常用字符 -[力扣题目链接](https://leetcode-cn.com/problems/find-common-characters/) +https://leetcode-cn.com/problems/find-common-characters/ 给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。 @@ -23,7 +23,7 @@ 【示例二】 输入:["cool","lock","cook"] 输出:["c","o"] - +  # 思路 @@ -40,9 +40,9 @@ 可以看出这是指数级别的时间复杂度,非常高,而且代码实现也不容易,因为要统计 重复的字符,还要适当的替换或者去重。 -那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)。 +那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)。 -如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://programmercarl.com/0242.有效的字母异位词.html)。 +如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)。 了解了哈希法,理解了数组在哈希法中的应用之后,可以来看解题思路了。 @@ -233,7 +233,41 @@ var commonChars = function (words) { return res }; ``` - +GO +```golang +func commonChars(words []string) []string { + length:=len(words) + fre:=make([][]int,0)//统计每个字符串的词频 + res:=make([]string,0) + //统计词频 + for i:=0;ib{ + return b + } + return a +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 52d2bc95..b60a8d1d 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -13,7 +13,7 @@ # 1047. 删除字符串中的所有相邻重复项 -[力扣题目链接](https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/) +https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/ 给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。 @@ -26,7 +26,7 @@ * 输入:"abbaca" * 输出:"ca" * 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。 - +  提示: * 1 <= S.length <= 20000 @@ -197,15 +197,38 @@ class Solution { Python: ```python3 +# 方法一,使用栈,推荐! class Solution: def removeDuplicates(self, s: str) -> str: - t = list() - for i in s: - if t and t[-1] == i: - t.pop(-1) + res = list() + for item in s: + if res and res[-1] == item: + res.pop() else: - t.append(i) - return "".join(t) # 字符串拼接 + res.append(item) + return "".join(res) # 字符串拼接 +``` + +```python3 +# 方法二,使用双指针模拟栈,如果不让用栈可以作为备选方法。 +class Solution: + def removeDuplicates(self, s: str) -> str: + res = list(s) + slow = fast = 0 + length = len(res) + + while fast < length: + # 如果一样直接换,不一样会把后面的填在slow的位置 + res[slow] = res[fast] + + # 如果发现和前一个一样,就退一格指针 + if slow > 0 and res[slow] == res[slow - 1]: + slow -= 1 + else: + slow += 1 + fast += 1 + + return ''.join(res[0: slow]) ``` Go: