leetcode 双指针

0 阅读7分钟

1. 删除有序数组重复项--easy

给你一个 非严格递增排列 的数组 nums ,请你原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k

判题标准:

系统会用下面的代码来测试你的题解:

 int[] nums = [...]; // 输入数组
 int[] expectedNums = [...]; // 长度正确的期望答案
 ​
 int k = removeDuplicates(nums); // 调用
 ​
 assert k == expectedNums.length;
 for (int i = 0; i < k; i++) {
     assert nums[i] == expectedNums[i];
 }

如果所有断言都通过,那么您的题解将被 通过

示例 1:

 输入:nums = [1,1,2]
 输出:2, nums = [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]
 解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 非严格递增 排列

我的题解----击败100%用户

 class Solution {
     public int removeDuplicates(int[] nums) {
         int k=0,p=0,q;
         int[] num=new int[nums.length];
         for(int i=1;i<=nums.length-1;i++){
             if(nums[p]!=nums[i]){
                 q=nums[i];
                 p+=1;
                 nums[p]=q;
             }
         }
         return p+1;
     }
 }

思路

  • 定义一个指针p,初始指向第一个位置。
  • 第二个指针循环数组,判断值与第一个指针的值是否相同。
  • 相同的话,不做操作
  • 不同的话,将p+1,然后将值赋给他。进行改变。

2. 删除数组元素--easy

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

 // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
 int len = removeElement(nums, val);
 ​
 // 在函数里修改输入数组对于调用者是可见的。
 // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
 for (int i = 0; i < len; i++) {
  print(nums[i]);
 }

示例 1:

 输入:nums = [3,2,2,3], val = 3
 输出:2, nums = [2,2]
 解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

 输入:nums = [0,1,2,2,3,0,4,2], val = 2
 输出:5, nums = [0,1,3,0,4]
 解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

我的题解---击败100%:

 class Solution {
     public int removeElement(int[] nums, int val) {
         int p=0,q;
         for(int i=0;i<nums.length;i++){
             if(nums[i]!=val){
                 nums[p]=nums[i];
                 p+=1;
             }
         }
         return p;
     }
 }

思路:

  • 定义一个指针,专门用来改变数组。
  • 循环数组,如果发现一个值与给定的值不同,则将这个值填入nums[p],然后p+1

3.找出字符串中第一个匹配项的下标-easy

给你两个字符串 haystackneedle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1

示例 1:

 输入:haystack = "sadbutsad", needle = "sad"
 输出:0
 解释:"sad" 在下标 0 和 6 处匹配。
 第一个匹配项的下标是 0 ,所以返回 0 。

示例 2:

 输入:haystack = "leetcode", needle = "leeto"
 输出:-1
 解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1

提示:

  • 1 <= haystack.length, needle.length <= 104
  • haystackneedle 仅由小写英文字符组成

我的题解:

 class Solution {
     public int strStr(String haystack, String needle) {
         int p=1;
         char[] a=haystack.toCharArray(),b=needle.toCharArray();//转换成字符串
         for(int i=0;i<haystack.length();i++){
             if(a[i]==b[0]){//第一个字符匹配
                 if(needle.length()==1){
                     return i;
                 }
                 for(int j=1;j<needle.length();j++){
                     if(i+j>a.length-1){
                         return -1;
                     }
                     if(a[i+j]==b[p]){
                         p+=1;
                     }
                     if(p==needle.length()){
                         return i;
                     }
                 }
             }
             p=1;
         }
         return -1;
     }
 }

思路:

题解1:

 class Solution {
     public int strStr(String haystack, String needle) {
         return haystack.indexOf(needle);
     }
 }

题解2---KMP算法:

 class Solution {
     // KMP 算法
     // ss: 原串(string)  pp: 匹配串(pattern)
     public int strStr(String ss, String pp) {
         if (pp.isEmpty()) return 0;
         
         // 分别读取原串和匹配串的长度
         int n = ss.length(), m = pp.length();
         // 原串和匹配串前面都加空格,使其下标从 1 开始
         ss = " " + ss;
         pp = " " + pp;
 ​
         char[] s = ss.toCharArray();
         char[] p = pp.toCharArray();
 ​
         // 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
         int[] next = new int[m + 1];
         // 构造过程 i = 2,j = 0 开始,i 小于等于匹配串长度 【构造 i 从 2 开始】
         for (int i = 2, j = 0; i <= m; i++) {
             // 匹配不成功的话,j = next(j)
             while (j > 0 && p[i] != p[j + 1]) j = next[j];
             // 匹配成功的话,先让 j++
             if (p[i] == p[j + 1]) j++;
             // 更新 next[i],结束本次循环,i++
             next[i] = j;
         }
 ​
         // 匹配过程,i = 1,j = 0 开始,i 小于等于原串长度 【匹配 i 从 1 开始】
         for (int i = 1, j = 0; i <= n; i++) {
             // 匹配不成功 j = next(j)
             while (j > 0 && s[i] != p[j + 1]) j = next[j];
             // 匹配成功的话,先让 j++,结束本次循环后 i++
             if (s[i] == p[j + 1]) j++;
             // 整一段匹配成功,直接返回下标
             if (j == m) return i - m;
         }
 ​
         return -1;
     }
 }
 ​
 作者:宫水三叶
 链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solutions/575568/shua-chuan-lc-shuang-bai-po-su-jie-fa-km-tb86/
 来源:力扣(LeetCode)
 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路:

  • 首先匹配串会检查之前已经匹配成功的部分中里是否存在相同的「前缀」和「后缀」。如果存在,则跳转到「前缀」的下一个位置继续往下匹配
  • 跳转到下一匹配位置后,尝试匹配,发现两个指针的字符对不上,并且此时匹配串指针前面不存在相同的「前缀」和「后缀」,这时候只能回到匹配串的起始位置重新开始
  • 难点就是找前缀和后缀,我们要先建立一个next预组,将这些信息存进去,next数组里的值代表的是已匹配的字符串前缀和后缀相同的长度
  • 检查「前缀」和「后缀」的目的其实是「为了确定匹配串中的下一段开始匹配的位置」。

4.反转字符串--easy

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须**原地修改输入数组**、使用 O(1) 的额外空间解决这一问题。

示例 1:

 输入:s = ["h","e","l","l","o"]
 输出:["o","l","l","e","h"]

示例 2:

 输入:s = ["H","a","n","n","a","h"]
 输出:["h","a","n","n","a","H"]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符

题解:

 class Solution {
     public void reverseString(char[] s) {
         int l=0,r=s.length-1;
         while(l<=r){
             char b=s[l];
             s[l]=s[r];
             s[r]=b;
             l++;
             r--;
         }
     }
 }