主要是双指针法相关题型的总结。
------------------------------
------------------------------
一、27 移除元素
题目描述:给你一个数组 nums 和一个值 val ,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
------------ python -----------
- class Solution:
- def removeElement(self, nums: List[int], val: int) -> int:
- slow=0
- fast=len(nums)-1
- while slow<=fast:
- if nums[slow]==val:
- nums[slow]=nums[fast]
- fast-=1
- else: slow+=1
- return slow
注意是返回元素数量,所以是返回slow,如果是下标就是slow-1
时间复杂度O(n)
------------ c++ -----------
- class Solution {
- public:
- int removeElement(vector<int>& nums, int val) {
- int p=0;
- int q=nums.size()-1;
- while(p<=q){
- if (nums[p]==val) nums[p]=nums[q--];
- else p++;
- }
- return p;
- }
- };
二、26 删除有序数组中的重复项
题目描述:给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
>>> 注意本题要求相对顺序保持一致。
------------ python -----------
- class Solution:
- def removeDuplicates(self, nums: List[int]) -> int:
- p=0
- for q in range(1,len(nums)):
- if nums[p]!=nums[q]:
- if q-p>1:
- nums[p+1]=nums[q]
- p+=1
- return p+1
------------ c++ -----------
- class Solution {
- public:
- int removeDuplicates(vector<int>& nums) {
- if(nums.empty()) return 0;
- int left=0;
- for(int needle=1;needle
size();needle++){ - if(nums[needle]!=nums[left]){
- if(needle-left>1) nums[left+1]=nums[needle];
- left++;
- }
- }
- return left+1;
- }
- };
三、283 移动零
题目描述:给定一个数组 nums ,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
------------ python -----------
- class Solution:
- def moveZeroes(self, nums: List[int]) -> None:
- """
- Do not return anything, modify nums in-place instead.
- """
- p=q=0
- while q<len(nums):
- if nums[q]!=0:
- nums[p],nums[q]=nums[q],nums[p]
- p+=1
- q+=1
左指针处理好的序列的尾部,右指针待处理的头部。 每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。
------------ c++ -----------
- class Solution {
- public:
- void moveZeroes(vector<int>& nums) {
- int i=0;
- for(int j=0;j
size();j++){ - if(nums[j]!=0){
- int tem=nums[i];
- nums[i]=nums[j];
- nums[j]=tem;
- i++;
- }
- }
- }
- };
四、844 比较含退格的字符串
题目描述:给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true。# 代表退格字符。
------------ python -----------
- class Solution:
- def backspaceCompare(self, s: str, t: str) -> bool:
- i,j=len(s)-1,len(t)-1
- skips=skipt=0 #存放#的数量
-
- while i>=0 or j>=0:
- while i>=0:
- if s[i]=="#":
- skips+=1
- i-=1
- elif skips>0:
- skips-=1
- i-=1
- else:
- break
- while j>=0:
- if t[j]=="#":
- skipt+=1
- j-=1
- elif skipt>0:
- skipt-=1
- j-=1
- else:
- break
- if i>=0 and j>=0:
- if s[i]!=t[j]:
- return False
- elif i>=0 or j>=0:
- return False
- i-=1
- j-=1
- return True
------------ c++ -----------
- class Solution {
- public:
- bool backspaceCompare(string s, string t) {
- int sn=s.size()-1;
- int tn=t.size()-1;
- int sc=0;
- int tc=0;
- while(sn>=0 || tn>=0){
- while(sn>=0){
- if(s[sn]=='#') sn--, sc++;
- else if(sc>0) sn--, sc--;
- else break;
- }
- while(tn>=0){
- if(t[tn]=='#') tn--, tc++;
- else if(tc>0) tn--, tc--;
- else break;
- }
- if(sn>=0 && tn>=0) {
- if(s[sn]!=t[tn]) return false;
- }
- else if(sn>=0 || tn>=0) return false;
- sn--, tn--;
- }
- return true;
- }
- };
五、977 有序数组的平方
题目描述:给你一个按 非递减顺序 排序的整数数组 nums ,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
------------ python -----------
- class Solution:
- def sortedSquares(self, nums: List[int]) -> List[int]:
- n = len(nums)
- ans = [0] * n
-
- i, j, pos = 0, n - 1, n - 1
- while i <= j:
- if nums[i] * nums[i] > nums[j] * nums[j]:
- ans[pos] = nums[i] * nums[i]
- i += 1
- else:
- ans[pos] = nums[j] * nums[j]
- j -= 1
- pos -= 1
-
- return ans
------------ c++ -----------
- class Solution {
- public:
- vector<int> sortedSquares(vector<int>& nums) {
- int i=0,j=nums.size()-1;
- vector<int> ans(nums.size(),0);
- for(int n=nums.size()-1;n>=0;n--){
- if(abs(nums[i])<=abs(nums[j])){
- ans[n]=nums[j]*nums[j];
- j--;
- }
- else{
- ans[n]=nums[i]*nums[i];
- i++;
- }
- }
- return ans;
- }
- };
六、344 反转字符串
题目描述:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
------------ python -----------
- class Solution:
- def reverseString(self, s: List[str]) -> None:
- """
- Do not return anything, modify s in-place instead.
- """
- left=0
- right=len(s)-1
- # while left!=right: 这么写在长度为偶数时会导致越界
- while left
- # s[left],s[right]=s[right],s[left]
- tem=s[left]
- s[left]=s[right]
- s[right]=tem
- left+=1
- right-=1
- return s
------------ c++ -----------
- class Solution {
- public:
- void reverseString(vector<char>& s) {
- int left=0;
- int right=s.size()-1;
- while (left
- // swap(s[left],s[right]);
- char ch=s[left];
- s[left]=s[right];
- s[right]=ch;
- left++;
- right--;
- }
- }
- };
七、替换数字
题目描述:给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
------------ python -----------
- class Solution:
- def change(self, s):
- lst = list(s) # Python里面的string也是不可改的,所以也是需要额外空间的。空间复杂度:O(n)。
- for i in range(len(lst)):
- if lst[i].isdigit():
- lst[i] = "number"
- return ''.join(lst)
------------ c++ -----------
- #include
- using namespace std;
- int main() {
- string s;
- while (cin >> s) {
- int sOldIndex = s.size() - 1;
- int count = 0; // 统计数字的个数
- for (int i = 0; i < s.size(); i++) {
- if (s[i] >= '0' && s[i] <= '9') {
- count++;
- }
- }
- // 扩充字符串s的大小,也就是将每个数字替换成"number"之后的大小
- s.resize(s.size() + count * 5);
- int sNewIndex = s.size() - 1;
- // 从后往前将数字替换为"number"
- while (sOldIndex >= 0) {
- if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
- s[sNewIndex--] = 'r';
- s[sNewIndex--] = 'e';
- s[sNewIndex--] = 'b';
- s[sNewIndex--] = 'm';
- s[sNewIndex--] = 'u';
- s[sNewIndex--] = 'n';
- } else {
- s[sNewIndex--] = s[sOldIndex];
- }
- sOldIndex--;
- }
- cout << s << endl;
- }
- }
八、151 翻转字符串里的单词
题目描述:给你一个字符串 s ,请你反转字符串中 单词 的顺序。单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。注意:输入字符串 s 中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
------------ python -----------
- class Solution:
- def reverseWords(self, s: str) -> str:
- # 删除前后空白
- s = s.strip()
- # 反转整个字符串
- s = s[::-1]
- # 将字符串拆分为单词,并反转每个单词
- s = ' '.join(word[::-1] for word in s.split())
- return s
- class Solution:
- def reverseWords(self, s: str) -> str:
- # 将字符串拆分为单词,即转换成列表类型
- words = s.split()
-
- # 反转单词
- left, right = 0, len(words) - 1
- while left < right:
- words[left], words[right] = words[right], words[left]
- left += 1
- right -= 1
-
- # 将列表转换成字符串
- return " ".join(words)
------------ c++ -----------
- class Solution {
- public:
- void reverse(string& s, int start, int end){ //翻转,区间写法:左闭右闭 []
- for (int i = start, j = end; i < j; i++, j--) {
- swap(s[i], s[j]);
- }
- }
-
- void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
- int slow = 0; //整体思想参考https://programmercarl.com/0027.移除元素.html
- for (int i = 0; i < s.size(); ++i) { //
- if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
- if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
- while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
- s[slow++] = s[i++];
- }
- }
- }
- s.resize(slow); //slow的大小即为去除多余空格后的大小。
- }
-
- string reverseWords(string s) {
- removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
- reverse(s, 0, s.size() - 1);
- int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
- for (int i = 0; i <= s.size(); ++i) {
- if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
- reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
- start = i + 1; //更新下一个单词的开始下标start
- }
- }
- return s;
- }
- };
九、206 反转链表
题目描述:反转一个链表。
------------ python -----------
- class Solution:
- def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
- if not head or not head.next:return head
- pre=None
- while head:
- nxt=head.next
- head.next=pre
- pre=head
- head=nxt
- return pre
- 》》》
- pre=None
- pre.next=head
- ————————————————
- AttributeError: 'NoneType' object has no attribute 'next'
- class Solution:
- def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
- if not head or not head.next:
- return head
- newhead=self.reverseList(head.next)
- head.next.next=head
- head.next=None
- return newhead
------------ c++ -----------
- class Solution {
- public:
- ListNode* reverseList(ListNode* head) {
- ListNode* pre=nullptr;
- while(head){
- ListNode* nxt=head->next;
- head->next=pre;
- pre=head;
- head=nxt;
- }
- return pre;
- }
- };
- class Solution {
- public:
- ListNode* reverseList(ListNode* head) {
- if(head==nullptr || head->next==nullptr) return head;
- ListNode* newhead=reverseList(head->next);
- head->next->next=head;
- head->next=nullptr;
- return newhead;
- }
- };
十、19 删除链表的倒数第N个结点
题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
------------ python -----------
- class Solution:
- def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
- pre=ListNode(0)
- pre.next=head
- fast=pre
- slow=pre
- while fast and n: #while n也可以
- fast=fast.next
- n-=1
- fast=fast.next
- while fast:
- fast=fast.next
- slow=slow.next
- slow.next=slow.next.next
- return pre.next
------------ c++ -----------
- class Solution {
- public:
- ListNode* removeNthFromEnd(ListNode* head, int n) {
- ListNode* dummyHead = new ListNode(0);
- dummyHead->next = head;
- //ListNode* slow=pre,fast=pre;
- //这样写会报错,c++无法自动推断fast类型(变量声明无法自动推导)
- ListNode* slow = dummyHead;
- ListNode* fast = dummyHead;
- while(n-- && fast != NULL) {
- fast = fast->next;
- }
- fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
- while (fast != NULL) {
- fast = fast->next;
- slow = slow->next;
- }
- slow->next = slow->next->next;
-
- // ListNode *tmp = slow->next; C++释放内存的逻辑
- // slow->next = tmp->next;
- // delete tmp;
-
- return dummyHead->next;
- }
- };
十一、160 链表相交
题目描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
------------ python -----------
- class Solution:
- def getIntersectionNode(self, A: ListNode, B: ListNode) -> Optional[ListNode]:
- if not A or not B: return None
- headA=A
- headB=B
- while A!=B:
- if A: A=A.next
- else: A=headB
- if B: B=B.next
- else: B=headA
- return A
------------ c++ -----------
- class Solution {
- public:
- ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
- if(!headA || !headB) return nullptr;
- ListNode *p1=headA;
- ListNode *p2=headB;
- while(p1!=p2){
- p1=p1!=nullptr?p1->next:headB;
- p2=p2!=nullptr?p2->next:headA;
- }
- return p1;
- }
- };
十二、142 环形链表2
题目描述:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
------------ python -----------
- class Solution:
- def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
- f=head
- s=head
- while f and f.next:
- s=s.next
- f=f.next.next
- if s==f:
- index1=f
- index2=head
- while index1!=index2:
- index1=index1.next
- index2=index2.next
- return index1
- return None
------------ c++ -----------
- class Solution {
- public:
- ListNode *detectCycle(ListNode *head) {
- ListNode* fast = head;
- ListNode* slow = head;
- #需要从同一点开始,不然会有偏差
- while(fast != NULL && fast->next != NULL) {
- slow = slow->next;
- fast = fast->next->next;
- // 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
- if (slow == fast) {
- ListNode* index1 = fast;
- ListNode* index2 = head;
- while (index1 != index2) {
- index1 = index1->next;
- index2 = index2->next;
- }
- return index2; // 返回环的入口
- }
- }
- return nullptr;
- }
- };
十三、15 三数之和
题目描述:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
------------ python -----------
- class Solution:
- def threeSum(self, nums: List[int]) -> List[List[int]]:
- result = []
- nums.sort()
-
- for i in range(len(nums)):
- # 如果第一个元素已经大于0,不需要进一步检查
- if nums[i] > 0:
- return result
-
- # 跳过相同的元素以避免重复
- if i > 0 and nums[i] == nums[i - 1]:
- continue
-
- left = i + 1
- right = len(nums) - 1
-
- while right > left:
- sum_ = nums[i] + nums[left] + nums[right]
-
- if sum_ < 0:
- left += 1
- elif sum_ > 0:
- right -= 1
- else:
- result.append([nums[i], nums[left], nums[right]])
-
- # 跳过相同的元素以避免重复
- while right > left and nums[right] == nums[right - 1]:
- right -= 1
- while right > left and nums[left] == nums[left + 1]:
- left += 1
-
- right -= 1
- left += 1
-
- return result
------------ c++ -----------
- class Solution {
- public:
- vector
int>> threeSum(vector<int>& nums) { - vector
int>> result; - sort(nums.begin(), nums.end());
- // 找出a + b + c = 0
- // a = nums[i], b = nums[left], c = nums[right]
- for (int i = 0; i < nums.size(); i++) {
- // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
- if (nums[i] > 0) {
- return result;
- }
- // 错误去重a方法,将会漏掉-1,-1,2 这种情况
- /*
- if (nums[i] == nums[i + 1]) {
- continue;
- }
- */
- // 正确去重a方法
- if (i > 0 && nums[i] == nums[i - 1]) {
- continue;
- }
- int left = i + 1;
- int right = nums.size() - 1;
- while (right > left) {
- // 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
- /*
- while (right > left && nums[right] == nums[right - 1]) right--;
- while (right > left && nums[left] == nums[left + 1]) left++;
- */
- if (nums[i] + nums[left] + nums[right] > 0) right--;
- else if (nums[i] + nums[left] + nums[right] < 0) left++;
- else {
- result.push_back(vector<int>{nums[i], nums[left], nums[right]});
- // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
- while (right > left && nums[right] == nums[right - 1]) right--;
- while (right > left && nums[left] == nums[left + 1]) left++;
-
- // 找到答案时,双指针同时收缩
- right--;
- left++;
- }
- }
-
- }
- return result;
- }
- };
十四、18 四数之和
题目描述:给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
------------ python -----------
- class Solution:
- def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
- nums.sort()
- n=len(nums)
- result=[]
-
- for i in range(n):
- if nums[i]>target and nums[i]>=0: #剪枝
- break
- if i>0 and nums[i]==nums[i-1]: #去重
- continue
- for j in range(i+1,n):
- if nums[i]+nums[j]>target and nums[i]+nums[j]>=0: #剪枝
- break
- if j>i+1 and nums[j]==nums[j-1]: #去重
- continue
- left,right=j+1,n-1
- while left
- s=nums[i]+nums[j]+nums[left]+nums[right]
- if s==target:
- result.append([nums[i], nums[j], nums[left], nums[right]])
- while left
and nums[left]==nums[left+1]: - left+=1
- while left < right and nums[right] == nums[right-1]:
- right -= 1
- left += 1
- right -= 1
- elif s
- left+=1
- else:
- right-=1
- return result
------------ c++ -----------
- class Solution {
- public:
- vector
int>> fourSum(vector<int>& nums, int target) { - vector
int>> result; - sort(nums.begin(), nums.end());
- for (int k = 0; k < nums.size(); k++) {
- // 剪枝处理
- if (nums[k] > target && nums[k] >= 0) {
- break; // 这里使用break,统一通过最后的return返回
- }
- // 对nums[k]去重
- if (k > 0 && nums[k] == nums[k - 1]) {
- continue;
- }
- for (int i = k + 1; i < nums.size(); i++) {
- // 2级剪枝处理
- if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
- break;
- }
-
- // 对nums[i]去重
- if (i > k + 1 && nums[i] == nums[i - 1]) {
- continue;
- }
- int left = i + 1;
- int right = nums.size() - 1;
- while (right > left) {
- // nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
- if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
- right--;
- // nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
- } else if ((long) nums[k] + nums[i] + nums[left] + nums[right] < target) {
- left++;
- } else {
- result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
- // 对nums[left]和nums[right]去重
- while (right > left && nums[right] == nums[right - 1]) right--;
- while (right > left && nums[left] == nums[left + 1]) left++;
-
- // 找到答案时,双指针同时收缩
- right--;
- left++;
- }
- }
-
- }
- }
- return result;
- }
- };
注:本文转载自blog.csdn.net的cherry_rainyyy的文章"https://blog.csdn.net/qq_51398395/article/details/143729920"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
评论记录:
回复评论: