0
点赞
收藏
分享

微信扫一扫

Python学习目录

zmhc 03-25 11:00 阅读 2

1 移动零

题目链接:https://leetcode.cn/problems/move-zeroes/description/

这道题要在原数组中交换位置,并且还要求算法有稳定性。我们的常规思路是划分数组,用双指针解决。

public static void doubleIndex3(int[] arr){
        for(int cur = 0,dest = -1 ; cur < arr.length; cur++) {
            if(arr[cur] != 0) {
                dest++;
                if(cur != dest) {
                    swap(arr , cur ,dest);
                }
            }
        }
    }

我们定义两个指针,desc 和 cur。数组左到desc是非零元素,desc到cur是0元素,0到数组末尾是待处理元素。这里就体现了数组划分。我们用cur遍历整个数组,在遍历过程中未处理元素会被依次添加到0区和非0区。因此,desc指向的是非零元素的最后一个元素。

代码中,要先让desc == -1,防止数组第一个元素是0,如果arr[cur]不为0,那就让desc++,并且,我们提到,数组左边到desc是非0区,所以如果遍历到的不是0,那么就要放到非0区,而放到非0区的做法就是交换desc后一位元素和当前元素的位置。直至遍历完整个数组。

时间复杂度O(n);

空间复杂度O(1);

相同拓展:

移除相同元素:

题目链接:27. 移除元素 - 力扣(LeetCode)
代码展示:
class Solution {
    public int removeElement(int[] nums, int val) {
        int desc = -1;
        int cur = 0;
        while(cur < nums.length) {
            if(nums[cur] != val) {
                desc++;
                if(cur != desc){
                     int tmp = nums[desc];
                    nums[desc] = nums[cur];
                    nums[cur] = tmp;
                }
                cur++;
            }else{
                cur++;
            }
        }
    
        return desc + 1;
    

    }
}

解题思路:

题目要求我们移除数组中值为value的元素,并返回其余元素的元素个数,那我们就可以将值为value的元素放到一边,不为value的元素放到另一边。最终返回的个数就是下标desc + 1即可。

2 复写零

题目链接:https://leetcode.cn/problems/duplicate-zeros/

这道题表示对数组原地操作,那我们就不申请数组,用原数组进行互换即可。

代码展示
class Solution {
    public void duplicateZeros(int[] arr) {
        int slow = 0;
        int fast = -1;
        while(fast < arr.length - 1){
            if(arr[slow] == 0) {
                fast = fast + 2;
            }
            else{
                fast++;
            }
            if(fast < arr.length - 1){
                slow++;
            }
        }
        if(fast == arr.length) {
            fast = arr.length - 2;
            slow--;
            arr[arr.length - 1] = 0;
        }
        while(slow < fast) {
            if(arr[slow] == 0){
                arr[fast--] = 0;
                arr[fast--] = 0;
            }
            else{
                arr[fast--] = arr[slow];
            }
            slow--;
        }

        }

    }
代码分析:

我们用的是双指针;

首先我们要找到最后一个要复写的元素;定义两个快慢指针,当慢指针等于零的时候,那么快指针走两步,慢指针走一步;此时慢指针每走一步都要判断快指针是否到达数组最后。如果到最后,那么慢指针就无需移动。注意点,要将快指针的起始值设置为1.

这个时候分析案例可知,有个特殊情况,当快指针在倒数第二个位置时,慢指针为0的话,此时快指针会走两步,那么快指针就会越界,这种情况下,当我们在复写的时候,末位置的0不需要复写,因为我们处理完这种特殊情况即可

第三步就是开始复写,每次复写完就将指针减减,直到两个指针相逢,那么此时剩下的元素均不要复写。

3 快乐数

题目链接:. - 力扣(LeetCode)
class Solution {
    public boolean isHappy(int count) {
         int slow = count;
        int fast = value(count);
        while(fast != slow) {
            slow = value(slow);
            fast = value(fast);
            fast = value(fast);
        }
        if(slow == 1) {
            return true;
        }
        return  false;
        
        
    } 
    public static int value(int count){
        int sum = 0;
        while (count > 0){
            int val = count % 10;
            sum = sum + val * val;
            count = count / 10;
        }
        return sum;
    }

    }
代码解析:
这道题类似于判断链表是否循环;

有题可知,一个数经过不断平方求和后都会循环,如果循环数均为1那么返回True,否则返回false。因此我们定义两个变量,一个一次变换两次,一个变换一次,因为形成的是圈,所以每次走两步的变量总会和每次走一步的变量相遇。所以只需要判断二者相遇的时候是否为1即可。

//以下的双指针题的原理通过单调性来实现

4 盛水最多的容器

题目链接:. - 力扣(LeetCode)​​​​​​
思路解析:

这道题要求我们找到数组间距乘以两元素之间乘积的最大值,我们一开始想到的暴力解法一定是将每个可能情况都枚举出来,然后比较。但是当我们稍微思考一下,就能发现,一个指针desc在0位置处,另一个指针cur在1位置,当我们后移cur时由于宽是增大的,所以当cur向后移的元素值大于当前元素值,那结果肯定是增大;我们要求的是最大值,因此当我们将两个指针放置数组两侧的时候,这样宽是最大的,因此在向中心移动过程中一旦遇到比当前值小的时候就能直接跳过。

此时我们要记住一个套路,通过单调性运用双指针的时候,两个指针应该交替都要移动,而不是一个指针固定,只让另一个指针移动;就是说,我们定义的两个指针cur和desc,哪个指针指向的元素小,哪个指针移动。

代码展示:
class Solution {
    public int maxArea(int[] arr) {
 int left = 0;
        int right = arr.length - 1 ;
        int max = 0;
        while(left < right){
             if(max < volume(arr,left,right)){
                 max = volume(arr , left ,right);
             }
            if(arr[left] < arr[right]) {
                int tmp = arr[left];
                left++;

                while(left < right && arr[left] < tmp ) {
                    left++;
                }
            }
            else {
                int tmp = arr[right];
                right--;
                while (left < right && arr[right] < tmp) {
                    right--;
                }
            }
        }
        return max;
    }
    public static int volume(int[] arr , int left , int right){
        if(arr[left] < arr[right]){
        return arr[left] * (right - left );
        }else {
            return arr[right] * (right - left );
        }
    }
}

我会分块讲解算法,后续会有动态规划,贪心,回缩,滑动窗口等

举报

相关推荐

0 条评论