《算法通过村第三关——白银挑战》

今天我们来学习一下数组中的双指针思想及其应用

我们为什么要学呢,因为在对数组的增删操作中,时常需要移动大量的元素,开销很大,所以就要用到双指针思想。接下来看一道题

LeetCode27.一个数组num和一个值val,要求移除所有值为val的元素,空间复杂度为O(1),元素的位置可以改变。

思路一:快慢指针

定义slow和fast两个指针,初始都在num[0]的位置,num[fast] != val时,两个指针一起移动,待找到val后,slow不懂,fast接着后移,当num[fast] != val时,开始移除元素。具体代码实现如下。

    public static int removeElement(int[] num,int val){
        int slow = 0;
        for (int fast =0;fast < num.length;fast++){
            if (num[fast] != val){
                num[slow] = num[fast];
                slow++;
            }
        }
        return slow;
    }

思路二:对撞双指针

数组两边各一个指针,当left == val且right != val的时候,将两个值交换,最后left的左边就是val全部删除后的数组

    public static int removeElement(int[] num,int val){
        int right = num.length-1;
        int left = 0;
        for (left=0;left <= right;){
            if (num[left] == val && num[right] != val){
                int tmp = num[left];
                num[left] = num[right];
                num[right] = tmp;
            }
            if (num[left] != val) left++;
            if (num[right] == val) right--;
        }
        return left;
    }

接下来再看一道题

给一个数组,例如num={0,0,1,1,1,2,2,3,3,4},要求删除重复的元素,但是保留一个。

思路:还是快慢指针,以num[fast] != num[slow]为关键条件。具体代码实现如下

    public static int removeElement(int[] num){
        int slow = 1;
        for (int fast =0;fast < num.length;fast++){
            if (num[fast] != num[slow-1]){
                num[slow] = num[fast];
                slow++;
            }
        }
        return  slow;
    }

——————————————————————————————————————————————————————————————————————————————————————

元素奇偶移动问题

给定一个数组,将其中偶元素移到前面,奇元素移到后面,两部分的内部顺序不要求。

思路:对撞型双指针

简单来说,左值为奇数且右值为偶数,则交换,否则两个指针继续前进

    public static int[] isSorted(int[] num){
        int left =0;
        int right = num.length-1;
        while (left < right){
            if ((num[left])%2 == 1 && (num[right])%2 ==0){
                int tmp = num[left];
                num[left] = num[right];
                num[right] = tmp;
            }
            if ((num[left])%2 == 0)   left++;
            if ((num[left])%2 == 1)    right--;

        }
        return num;
    }

——————————————————————————————————————————————————————————————————————————————————————

数组轮转问题

一个数组,向右轮转k个位置(k <0),例如num{1,2,3,4,5},k=1,则结果为num{5,1,2,3,4}

思路:先将整个数组反转一下,再按照k将其分成两个部分,再分别反转。代码如下

    public void rotate(int[] num,int k){
        k %= num.length;
        reverse(num,0,num.length-1);
        reverse(num,0,k-1);
        reverse(num,k,num.length-1);
    }
    public void reverse(int[] num,int start,int end){
        while (start < end){
            int tmp = num[end];
            num[end] = num[start];
            num[start] = tmp;
            start++;
            end--;
        }
    }

——————————————————————————————————————————————————————————————————————————————————————

数组的区间问题

LeetCode228.给一个数组num{0,1,2,4,5,7},我们可以将其分为三个区间1->2,4->5,7.可见,区间可以有一个或多个元素。

那么我们可以怎么实现呢

思路:使用快慢指针,在fast到达最后一个元素,或者遇到不+1递增的情况时,及时分组。

具体代码如下

    public  static List<String> summaryRanges(int[] num){
        List<String> res = new ArrayList<>();
        int slow =0;
        for (int fast =0;fast < num.length;fast++){
            if (fast+1 ==num.length || num[fast] +1 != num[fast + 1]){
                StringBuilder sb = new StringBuilder();
                sb.append(num[slow]);
                if (slow != fast){
                    sb.append("->").append(num[fast]);
                }
                res.add(sb.toString());
                slow = fast+1;
            }
        }
        return res;
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值