双指针思想以及应用-leetcode

41 阅读5分钟

1.双指针思想

2.删除元素专题

2.1原地移除所有数值等于val的元素

leetcode27,移除元素 给你一个数组 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,4,0,3] 解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。 :::info 思路: 很容易就想到双指针 :::

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

    }
}

2.2删除有序数组中的重复项

删除有序数组的重复项 给你一个 非严格递增排列 的数组 nums ,请你原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

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

  • 返回 k 。

示例 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 。不需要考虑数组中超出新长度后面的元素。

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums.length==1){
            return 1;
        }
        int index=0;
        for (int i = 1; i < nums.length; i++) {
            if(nums[index]!=nums[i]){
                nums[++index]=nums[i];
            }
        }
        return index+1;

    }
}

3.元素奇偶移动专题

按奇偶排序数组

class Solution {
    public int[] sortArrayByParity(int[] nums) {
        int j=0;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i]%2==0){
                int temp=nums[i];
                nums[i]=nums[j];
                nums[j++]=temp;
            }
        }
        return nums;

    }
}

4.数组轮转问题

数组轮转 :::info 思路1: 创建一个新数组,按照顺序存进去,再赋值给原数组 思路2:

  1. 首先对整个数组实行翻转,这样子原数组中需要翻转的子数组,就会跑到数组最前面。
  2. 这时候,从 k 处分隔数组,左右两数组,各自进行翻转即可。 :::
class Solution {
    public void rotate(int[] nums, int k) {
        //方法二
        int x=k%nums.length;
        reverseArr(nums,0,nums.length-1);
        reverseArr(nums,0,x-1);
        reverseArr(nums,x,nums.length-1);




        //方法一
/*        int x=k%nums.length;
        int[] arr=new int[nums.length];
        int index=0;
        for (int i = nums.length-x; i < nums.length; i++) {
            arr[index++]=nums[i];
        }
        for (int i = 0; i < nums.length-x; i++) {
            arr[index++]=nums[i];
        }
        int j=0;
        for (int i = 0; i < nums.length; i++) {
            nums[i]=arr[j++];
        }*/


    }

    private void reverseArr(int[] nums, int l, int r) {
        while (l<r){
            int temp=nums[l];
            nums[l]=nums[r];
            nums[r]=temp;
            l++;
            r--;
        }
    }
}

5.数组区间问题

汇总区间 :::info 思路: 定义两个指针:l,r 遍历数组: 拼接条件r+1==nums.length||nums[r]+1!=nums[r+1] :::

class Solution {

    public static List<String> summaryRanges(int[] nums) {
        List<String> list=new ArrayList<>();
        int l=0;
      
        for (int r=0; r < nums.length; r++) {
            if(r+1==nums.length||nums[r]+1!=nums[r+1]){
                if(r==l){
                    list.add(String.valueOf(nums[l]));
                }else {
                    list.add(nums[l]+"->"+nums[r]);
                }
                l=r+1;
            }
          
        }

        return list;

    }
}

6.字符串替换空格问题

这是剑指offr中的题目,出现频率也很高:请实现一个函数,将一个字符串中的每个空格替换成 "%20”。例如,当字符串为We Are Happy..则经过替换之后的字符串为We%20Are%20 Happy.. 首先要考虑用什么来存储字符串,如果是长度不可变的char数组,那么必须新申请一个更大的空间。如果 使用长度可变的空间来管理原始数组,或者原始数组申请得足够大,这时候就可能要求你不能申请0(n)大 小的空间,我们一个个看。 思路:首先扩充数组到每个空格替换成"%20"之后的大小。 然后从后向前替换空格,也就是双指针法,过程如下: i指向新长度的末尾,j指向旧长度的末尾。

public class Solution {
   public static void main(String[] args) {
      String s="hello world ";
      System.out.println(replaceSpace(s));
   }


   public static String replaceSpace(String s){
      if(s==null||s.length()==1){
         return s;
      }
      //扩充空间,空格数量的两倍
      StringBuilder str=new StringBuilder();
      for (int i = 0; i < s.length(); i++) {
         if(s.charAt(i)==' '){
            str.append("  ");
         }
      }
      //没有空格,直接返回即可
      if(str.length()==0){
         return s;
      }
      //有空格,定义双指针
      int l=s.length()-1;
      s+=str.toString();
      int r=s.length()-1;
      char[] chars = s.toCharArray();
      for(;l>=0;l--){
         if(chars[l]==' '){
            chars[r--]='0';
            chars[r--]='2';
            chars[r--]='%';
         }else {
            chars[r--]=chars[l];
         }

   }
      return new String(chars);


   }
}