日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LeetCode算法题5:双指针

發布時間:2025/6/17 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode算法题5:双指针 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 一、有序數組的平方
  • 二、輪轉數組
  • 三、移動零
  • 四、兩數之和 II - 輸入有序數組
  • 五、反轉字符串
  • 六、反轉字符串中的單詞 III
  • 七、鏈表的中間結點
  • 八、刪除鏈表的倒數第 N 個結點
  • 總結


前言

??????Leetcode算法系列:https://leetcode-cn.com/study-plan/algorithms/?progress=njjhkd2

??????簡單總結一下雙指針相關的算法題:

一、有序數組的平方

??????題目鏈接:https://leetcode-cn.com/problems/squares-of-a-sorted-array/

??????題目描述:給你一個按 非遞減順序 排序的整數數組 nums,返回 每個數字的平方 組成的新數組,要求也按 非遞減順序 排序。

??????思路1:因為有可能存在負數,所以從數組的兩端開始計算,因為數組元素平方的最大值不是在開頭,就是在末尾,由此可得下面解法:

class Solution {public int[] sortedSquares(int[] nums) {int[] res=new int[nums.length];int start=0,end=nums.length-1;for(int ri=end;ri>=0;ri--){ //從后往前 從兩邊向中間收縮。int t1=nums[start]*nums[start];int t2=nums[end]*nums[end];if(t1<t2){res[ri]=t2;end--;}else{res[ri]=t1;start++;}}return res;} }

??????相反的,如果想從最小值的兩邊開始擴散則不太容易。因為在這樣一個非降序排列的數組中不太好直接找到絕對值最小的那個值。那么可以考慮先對原數組求平方,然后再找最小值。由此得到思路2。

??????思路2:從最小值開始往兩邊擴散有一種更好的方法:先對原數組求平方之后,再找到最小值然后擴散即可。可參考算法如下:

public int[] sortedSquares(int[] nums) {int len=nums.length-1,i;for(i=0;i<=len;i++)nums[i]=nums[i]*nums[i];int minIndex=0;for(i=1;i<=len;i++)if(nums[minIndex]>nums[i])minIndex=i;int[] ans=new int[len+1];i=0;ans[i++]=nums[minIndex];int left=minIndex-1,right=minIndex+1;while(left>=0&&right<=len){if(nums[left]<nums[right]){ans[i++]=nums[left];left--;}else{ans[i++]=nums[right];right++;} }while(left>=0){ans[i++]=nums[left];left--;}while(right<=len){ans[i++]=nums[right];right++;}return ans;}

??????這兩種做法的時間復雜度和空間復雜度都為O(n)。

二、輪轉數組

??????題目鏈接:https://leetcode-cn.com/problems/rotate-array/

??????題目描述:給你一個數組,將數組中的元素向右輪轉 k 個位置,其中 k 是非負數。

??????思路:假設數組長度為 len,k=len 或 =0 時,原數組不會產生變化,所以需要取模來避免不必要的運算。 令 k = k%len 。有一種比較巧妙的解法是進行兩次逆序,參考如下:

class Solution {public void rotate(int[] nums, int k) {int len=nums.length,k1=k%len;int tmp;int i=0,j=len-1;while(i<j){ // 逆序(第一次)tmp=nums[i];nums[i]=nums[j];nums[j]=tmp;i++;j--;}for(i=0,j=k1-1;i<j;i++,j--){ //分別逆序(左半部分第二次)tmp=nums[i];nums[i]=nums[j];nums[j]=tmp;}for(i=k1,j=len-1;i<j;i++,j--){ //分別逆序(右半部分第二次)tmp=nums[i];nums[i]=nums[j];nums[j]=tmp;}} }

??????時間復雜度為O(n),空間復雜度為O(1)。

??????思路2:更直觀的,如果我們新建一個數組,這道題立馬就變得簡單,但是空間復雜度也變為O(n)了。

public void rotate(int[] nums, int k) {int len=nums.length,k1=k%len; // 注意:k 個元素輪轉k次為其本身。if(k1==0)return;int index=len-k1; //index 為起始下標。int[] tmp=Arrays.copyOf(nums,len);int i,j=0;for(i=index;i<len;i++)nums[j++]=tmp[i];for(i=0;i<index;i++)nums[j++]=tmp[i];}

??????思路3:想象一下這個數組是一個循環數組(參考循環隊列),k 表示所有元素向右移動 k 次,這個時候最終元素的位置就需要對數組長度取模了,經過一丟丟的運算,下標為 index 的數的最終位置為 (index+k)%len,len 為數組長度。參考算法如下(空間復雜度仍為O(n)):

public void rotate(int[] nums, int k) {int len=nums.length,k1=k%len;int[] tmp=Arrays.copyOf(nums,len);for(int i=0;i<len;i++){nums[(i+k1)%len]=tmp[i];}

??????思路4:將 3 的空間復雜度優化降低為O(1),缺點是算法會稍微顯得有些復雜,參考如下:

public void rotate(int[] nums, int k) {//注意:不重復的幾輪交替轉換一定會搞定,一定不會存在重復交換的情況。int len=nums.length,k1=k%len;int count=0;int indexNew,valueOld,valueNew;for(int i=0;count!=len;i++){ // i一定不會增加到len。indexNew=(i+k1)%len;valueOld=nums[i];valueNew=nums[indexNew];while(i!=indexNew){nums[indexNew]=valueOld;valueOld=valueNew;indexNew=(indexNew+k1)%len;valueNew=nums[indexNew];count++;}nums[i]=valueOld; //最后收尾。count++;}

三、移動零

??????題目鏈接:https://leetcode-cn.com/problems/move-zeroes/

??????題目描述:給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。
??????請注意 ,必須在不復制數組的情況下原地對數組進行操作。

??????思路1:從頭開始遍歷數組,當遇到一個 0 時,將0之后的所有元素均往前移動一位,最后一個數置為0;下一次再遇到 0,依然將此 0 之后的所有元素往前移動一位,也將最后一個數置為0。 算法的時間復雜度為O(n2)。參考算法:

public void moveZeroes(int[] nums) {int len=nums.length;int i,j,countZero=0; for(i=0;i<len-countZero;){if(nums[i]==0){countZero++;for(j=i;j<len-1;j++)nums[j]=nums[j+1];nums[j]=0;}elsei++; }}

??????思路2:雙指針,首先,一個指針 a 標記數組中出現的第一個零,另一個指針 b 標記在 a 之后的第一個非零數,因為可能有連續的 0 存在,所以 b 并不總等于 a+1。
??????然后,重復執行 “交換 a 和 b 所指向的值,再令 a++,此時 a 所指向的元素必為0;增加 b 的值,直到它指向下一個非零數(或者指向數組尾,此時算法結束)”。時間復雜度為O(n)。參考算法:

public void moveZeroes(int[] nums) {int len=nums.length,a=0,b=0;while(a<len&&nums[a]!=0)a++;b=a+1;while(b<len&&nums[b]==0)b++;while(b<len){nums[a]=nums[b];nums[b]=0;a++;while(b<len&&nums[b]==0)b++;} }

??????思路2 也可以用下面的算法來實現:

public void moveZeroes(int[] nums) {int indexNow = 0,indexNum = 0,len = nums.length;while(indexNum<m){if(nums[indexNum] != 0) nums[indexNow++] = nums[indexNum];++indexNum;}for(int i = indexNow; i < m; i++)nums[i] = 0;}

四、兩數之和 II - 輸入有序數組

??????題目鏈接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/

??????題目描述:給你一個下標從 1 開始的整數數組 numbers ,該數組已按 非遞減順序排列 ,請你從數組中找出滿足相加之和等于目標數 target 的兩個數。如果設這兩個數分別是 numbers[index1] 和 numbers[index2] ,則 1 <= index1 < index2 <= numbers.length 。

??????以長度為 2 的整數數組 [index1, index2] 的形式返回這兩個整數的下標 index1 和 index2。

??????你可以假設每個輸入 只對應唯一的答案 ,而且你 不可以 重復使用相同的元素。

??????你所設計的解決方案必須只使用常量級的額外空間。

??????思路1:二分查找:從第一個數開始,在之后的數中查找另一個數,使得二者之和等于target,存在即返回,否則遍歷數組直至結束。時間復雜度為O(nlogn)。參考算法:

public int[] twoSum(int[] numbers, int target) {for (int i = 0; i < numbers.length; ++i) {int low = i + 1, high = numbers.length - 1;while (low <= high) {int mid = (high - low) / 2 + low;if (numbers[mid] == target - numbers[i]) return new int[]{i + 1, mid + 1};else if (numbers[mid] > target - numbers[i]) high = mid - 1;else low = mid + 1;}}return new int[]{-1, -1};}

??????思路2:雙指針,由于此數組為非遞減,令指針 index1 指向數組第一個元素,令指針 index2 指向數組第二個元素,當這兩處元素之和大于 target 時,只能減小 index2;小于 target 時,只能增大 index1;等于 target 時,算法結束。時間復雜度為O(n)。參考算法:

public int[] twoSum(int[] numbers, int target) {int index1=0,index2=numbers.length-1;int tmp;while(index1<index2){tmp=numbers[index1]+numbers[index2];if(tmp==target)return new int[]{index1+1,index2+1};else if(tmp<target)index1++;elseindex2--;}return null;}

五、反轉字符串

??????題目鏈接:https://leetcode-cn.com/problems/reverse-string/

??????題目描述:編寫一個函數,其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 s 的形式給出。

??????不要給另外的數組分配額外的空間,你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。

??????思路:雙指針,首尾元素交換即可。時間復雜度為O(n)。參考算法:

public void reverseString(char[] s) {int index1=0,index2=s.length-1;char tmp;while(index1<index2){tmp=s[index1];s[index1]=s[index2];s[index2]=tmp;index1++;index2--;}}

六、反轉字符串中的單詞 III

??????題目鏈接:https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/

??????題目描述:給定一個字符串 s ,你需要反轉字符串中每個單詞的字符順序,同時仍保留空格和單詞的初始順序。

??????思路:雙指針,一個指針每次指向字符串中單詞的開頭,另一個指針指向單詞的末尾,反轉即可。時間復雜度為O(n),空間復雜度為O(1)。參考算法:

public String reverseWords(String s) {char[] ss=s.toCharArray();int index1=0,index2;int len=ss.length;char tmp;for(int i=0;i<=len;i++){if(i==len||ss[i]==' '){ //將上面的代碼稍微優化一下,減少了原來的代碼量。index2=i-1;while(index1<index2){tmp=ss[index2];ss[index2]=ss[index1];ss[index1]=tmp;index2--;index1++;}index1=i+1; }}return new String(ss); }

七、鏈表的中間結點

??????題目鏈接:https://leetcode-cn.com/problems/middle-of-the-linked-list/

??????題目描述:給定一個頭結點為 head 的非空單鏈表,返回鏈表的中間結點。如果有兩個中間結點,則返回第二個中間結點。

??????思路1:簡單的做法,遍歷兩次,第一次得到鏈表的長度;第二次返回鏈表的中間結點。參考算法:

public ListNode middleNode(ListNode head) {int len=0;ListNode tmp;for(tmp=head;tmp!=null;tmp=tmp.next)len++;int mid=len/2,i=0;for(tmp=head;i<mid;i++)tmp=tmp.next;return tmp;}

??????思路2:雙指針,兩個指針之間的關系為:一個指針 index2 一次跑兩步,另一個指針 index1 一次跑一步。這里需要注意比如結點總數為 2 或者 3 時,返回的中間節點是相同的。參考算法:

public ListNode middleNode(ListNode head) {ListNode index1,index2;index1=index2=head;while(index2!=null&&index2.next!=null){ //節點總數為3時,index1仍為總數為2的結果,沒有發生改變。index2=index2.next.next;index1=index1.next;}return index1;}

八、刪除鏈表的倒數第 N 個結點

??????題目鏈接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/

??????題目描述:給你一個鏈表,刪除鏈表的倒數第 n 個結點,并且返回鏈表的頭結點。

??????思路1:基于上題的經驗,直接采用雙指針來做,僅需要修改兩個指針之間的關系為:保持兩個指針之間的距離恒定為 n。這樣,當指針 index2 指向鏈表尾時,index1 為待刪除結點的前一個結點,然后進行刪除操作。但是還需要考慮刪除第一個結點的情況,所以在剛開始時,我創建了一個 dummy 結點,它的 next 指向頭節點,這樣就方便多了。參考算法:

public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummy,index1,index2;dummy=new ListNode(-1,head);//dummy 結點index1=dummy;index2=head;int count=0;while(index2!=null){index2=index2.next;count++;if(count>n)index1=index1.next;}index1.next=index1.next.next;return dummy.next;}

??????注,不管是通過計算鏈表長度的方式,還是通過建立輔助棧的解法,都沒有雙指針來的簡潔。


總結

??????無。

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的LeetCode算法题5:双指针的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。