算法题总结(二)——双指针

双指针

27、移除元素

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

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

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

正常的思路:两个for循环一个循环找到val,一个循环进行元素的移动。

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置,即新数组下一个元素的位置

快指针遍历一遍数组,寻找元素,把符合条件的元素记录到新数组中(即移除不符合条件的元素

),用一个指针记录新数组要插入的位置,就可以不需要额外的空间复杂度。

判断元素与某个值是否相等,从0开始判断。

class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        int slowIndex = 0;   
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}

26、删除有序数组中的重复项

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

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

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

即某个元素需要被删除的条件:和前一个元素相等

需要被保留的条件:和前一个元素不相等,即是唯一的

class Solution {
    public int removeDuplicates(int[] nums) {
        int slowIndex=1; //新数组要被放入的位置,因为条件是和前一个元素相比是否相等,所以从1开始判断。
        for(int fastIndex=1;fastIndex<nums.length;fastIndex++)
        {
            if(nums[fastIndex]!=nums[fastIndex-1])  
                //元素需要被保留下来的条件
            {
                nums[slowIndex]=nums[fastIndex];
                slowIndex++;
            }

        }
        return slowIndex;

    }
}

方法二:while循环,即需要手动进行fastIndex++;

class Solution {
    public int removeDuplicates(int[] nums) {
        int fastIndex=1;
        int slowIndex=1;  //第一个元素一定是不重复的,因此从第二个开始

        while(fastIndex<nums.length) //快指针 寻找元素
        {
            if(nums[fastIndex]!=nums[fastIndex-1])  //说明这个元素是唯一的
            {
                nums[slowIndex]=nums[fastIndex];
                slowIndex++;
                fastIndex++;
            }
            else{    //有重复元素,只有fastIndex向后移动
                fastIndex++;
            }
        }
        return slowIndex;



    }
}

283、移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

即需要保留的是非零元素,然后在末尾处补零

class Solution {
    public void moveZeroes(int[] nums) {
        int slowIndex=0;
        int fastIndex=0;

        while(fastIndex<nums.length)
        {
            if(nums[fastIndex]!=0)
            {
                nums[slowIndex]=nums[fastIndex];
                slowIndex++;
                fastIndex++;
            }
            else{
                fastIndex++;
            }
        }
        for(int i=slowIndex;i<nums.length;i++){
            nums[i]=0;
        }


    }
}

844、比较含退格的字符串

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。

示例 2:

输入:s = "ab##", t = "c#d#"
输出:true
解释:s 和 t 都会变成 ""。

示例 3:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。

即不为# 则是满足条件的元素,要保存,如果遇到#,则slowIndex需要回退来代表删除

class Solution {
    public boolean backspaceCompare(String s, String t) {

        //return block(s)==block(t);
        return block(s).equals(block(t));

    }

    public String block(String s)
    {

        char[] chars=s.toCharArray();
        int slowIndex=0; //新数组下一个元素的位置
        for(int fastIndex=0;fastIndex<chars.length;fastIndex++)
        {
            if(chars[fastIndex]!='#'){
                chars[slowIndex]=chars[fastIndex];
                slowIndex++;
            }
            else if(chars[fastIndex]=='#' && slowIndex>0)  
                //如果是#符号,慢指针回退
            {
                slowIndex--;   
            }
        }
        //slowIndex的位置就是下一个要插入的元素的位置,也是我们元素的个数。
        //copyOf会复制0 - slowIndex-1的元素
        char[] newchars=Arrays.copyOf(chars,slowIndex);

        //再转换成字符串
        return Arrays.toString(newchars);

    }


}

977、有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

一定要利用有序性,即平方后先递减再递增

方法一:从中间开始,采用双指针进行比较,类似于并归排序

class Solution {
    public int[] sortedSquares(int[] nums) {
        //本质上就是对平方后的数组进行排序,对于普通的数组来说,复杂度最低
        //是nlogn,由于这个原来的是有序的,所以,这个数组先递减再递增

        //找到正负数分解线
        int pos=0;
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]<0)
            {
                pos=i;       //找到的pos是最后一个负数
            }
        }
        //每个元素平方
        for(int i=0;i<nums.length;i++)
        {
            nums[i]=nums[i]*nums[i];
        }
        //并归排序
        int next=pos+1;
        int index=0;
        int[] ans = new int[nums.length];  //注意这里int后要用[]
        while(pos>=0 && next<nums.length)
        {
            if(nums[pos]<=nums[next])
            {
                ans[index++]=nums[pos--];
            }
            else if(nums[pos]>nums[next])
            {
                ans[index++]=nums[next++];
            }
        }
        if(pos<0)
        {
            while(next<nums.length)
            {
                ans[index++]=nums[next++];

            }
        }
        if(next>=nums.length)
        {
            while(pos>=0)
            {
                ans[index++]=nums[pos--];
            }
        }
        return ans;
    }
}

可以先平方后再排序,也可以边平方边排序

方法二:平方后从两端开始用双指针比较,倒序装入新数组中

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left=0;
        int right=nums.length-1;
        int[] result=new int [nums.length];
        int index=nums.length-1;
        //平方
        for(int i=0;i<nums.length;i++)
        {
            nums[i]=nums[i]*nums[i];
        }
        while(left<=right)  //要相等,否则奇数的时候就会漏掉一个元素
        {
            if(nums[left]>nums[right])
            {
                result[index--]=nums[left++];
            }
            else
            {
                result[index--]=nums[right--];
            }
        }
        return result;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值