leetcode算法21天:第二天

双指针

说到双指针,其实最容易想到的是快速排序方法。使用两个指针,通过哨兵比较,形成局部有序。

第一题:有序数组的平方

java答案:

class Solution {
    public int[] sortedSquares(int[] nums) {
        int i=0,j=nums.length-1;
        int flag=nums.length-1;
        int[] bnums=new int[nums.length];
        while(i<=j){
            if(nums[i]*nums[i]>nums[j]*nums[j]){
                bnums[flag]=nums[i]*nums[i];
                i++;               
            }
            else{
                bnums[flag]=nums[j]*nums[j];
                j--;
            }
            flag--;
        }
        return bnums;
    }
}

当然,也不一定上来就比较数组第一个值和最后一个值的平方大小,也可以判断出正负数交接的下表,这样的话,出现全是正或者全是负比较快速一点。

第二题:旋转数组

题目描述:

第一种解法:

我们一般能想到使用另外的一个数组

class Solution {
    public void rotate(int[] nums, int k) {
        int[] bnums=new int[nums.length];
        for(int i=0;i<nums.length;i++){
            bnums[(i+k)%nums.length]=nums[i];
        }
        System.arraycopy(bnums, 0, nums, 0, nums.length);

    }
}

  • 时间复杂度: O(n)O(n),其中 nn 为数组的长度。

  • 空间复杂度: O(n)O(n)。

需要讲讲System.arraycopy

public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

其中参数含义:

Object src:the source array. 源数组
int srcPos:starting position in the source array. 在源数组中,开始复制的位置
Object dest:the destination array. 目标数组
int destPos:starting position in the destination data. 在目标数组中,开始赋值的位置
int length:the number of array elements to be copied. 被复制的数组元素的数量

要注意:数组越界,取原数组的时候,int srcPos和int length要注意不要超过原始数组的范围,同时目标数组destPos和length也要注意不要超过目标数组的范围。

System.arraycopy为 JVM 内部固有方法,它通过手工编写汇编或其他优化方法来进行 Java 数组拷贝,这种方式比起直接在 Java 上进行 for 循环或 clone 是更加高效的。数组越大体现地越明显。

arraycopy的深拷贝和浅拷贝

  1. 当数组为一维数组,且元素为基本类型或String类型时,属于深复制,即原数组与新数组的元素不会相互影响(String的特殊是因为它的不可变性)
  2. 当数组为多维数组,或一维数组中的元素为引用类型时,属于浅复制,原数组与新数组的元素引用指向同一个对象

第二种解法:

例如:当k=3时

class Solution {
    public void rotate(int[] nums, int k) {
        //一定不要忘了这一步,不然有可能会出现数组越界的错误,找了半天
        k = k % nums.length;
        reserver(nums,0,nums.length-1);
        reserver(nums,0,k-1);
        reserver(nums,k,nums.length-1);
              
    }

    public static int[] reserver(int[] nums,int low,int high){
            for(;low<high;low++,high-- ){
            int temp=nums[low];
            nums[low]=nums[high];
            nums[high]=temp;
        }
        return nums;
        
    }
}

时间复杂度:O(n),其中 n 为数组的长度。每个元素被翻转两次,一共 n 个元素,因此总时间复杂度为 O(2n)=O(n)。

空间复杂度:O(1)。

 

踩坑提示:

说我数组越界,这一行报错,检查老久了,被自己蠢哭。

第三种解法:

上图中pre,next,  a[next]=a[pre];count在下面的代码中没有体现,直接比对的是下标直接回到一个循环起始的地方

class Solution {
    public void rotate(int[] nums, int k){
        int n=nums.length; 
        //求公约数      
        int count = gcd(k, n);
        for(int start=0;start<count;start++){
            //pre记录的是拿去覆盖的值,例如a[2]=a[0],这里记录的是a[0]
            int pre=nums[start];
            int next=start;
            do{
                //记录下一次的位置,例如下标为1的值,会插入到1+k的位置;例如:k=2时,a[2]=a[0],next代表这个2
                next=(next+k)%n;
                //因为a[2]=a[0],a[2]的值会被覆盖,需要先把a[2]的值存起来
                int temp=nums[next];
                //这步实现a[2]=a[0]
                nums[next]=pre;
                //pre记录的是a[2]的值,pre记录的是去覆盖的值
                pre=temp;
            }while(start!=next);         
        }
    }

    public int gcd(int x, int y) {
        return y > 0 ? gcd(y, x % y) : x;
    }
}

这里需要注意公约数和循环的圈有几次

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值