由LeetCode 581. Shortest Unsorted Continuous Subarray引发的对数组的深入思考(值&引用,复制数组)

LeetCode 581. Shortest Unsorted Continuous Subarray

Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order, too.

You need to find the shortest such subarray and output its length.

Example 1:

Input: [2, 6, 4, 8, 10, 9, 15]
Output: 5
Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order.

Note:

  1. Then length of the input array is in range [1, 10,000].
  2. The input array may contain duplicates, so ascending order here means <=.

思路:对数组进行排序,排序以后看看首尾共有多少元素与原数组相等,其余的元素就是所求的最短无序连续子数组。

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int[] arr = nums;
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
        System.out.println(Arrays.toString(nums));
        System.out.println(arr.equals(nums));
        int res =0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]==arr[i]) res++;
            else break;
        }
        if(res==nums.length) return 0;
        for(int i=nums.length-1;i>0;i--){
            if(nums[i]==arr[i]) res++;
            else break;
        }
        return nums.length-res;
    }
}

结果有些意外,arr和nums数组竟然相等。

究竟是怎么回事呢???

借用《Java编程思想》的例子和解释:

public class ArrayOptions {
    public static void main(String[] args) {
        BeryllumSphere[] a;
        BeryllumSphere[] d = { new BeryllumSphere(), new BeryllumSphere(), new BeryllumSphere() };
        a = new BeryllumSphere[] { new BeryllumSphere(), new BeryllumSphere() };
        System.out.println("d.length" + d.length());
        a = d;
        System.out.println("a.length" + a.length());
    }
}
/*Output:
d.length=3
a.length=3
*/

表达式:a=d;

将指向某个数组对象的引用赋给另一个数组对象,这与其他类型的对象引用没什么区别。现在a与d都指向堆中的同一个数组对象。

当然,也许你会有和我一样的疑问。

private static void exch(int[] arr, int i, int j) {
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }

那为什么上面交换操作就可以呢?数组就不行呢?为什么差别对待呢?

Java讲究“一切都是对象”,但操纵的标识符实际上是对象的一个“引用”(reference)。举个例子,用遥控器(引用)来操纵电视机(对象)。数组的标识符其实只是一个引用,指向在堆中创建的一个真实对象。

特例:基本类型。之所以特殊对待,是因为new将对象存储在“堆”里面,故用new创建一个对象——特别是小的、简单的变量,往往不是很有效。因此,对于这些类型,Java采取与C和C++相同的方法。也就是说,不用new来创建变量,而是创建一个并非是引用的“自动”变量。这个变量直接存储“值”,并置于堆栈中,因此更加高效。

这也就不难理解为什么会出现上面的情况了,“int[] arr = nums;”将一个数组赋值给另一个数组,其实真正做的只是复制了一个引用。由于nums和arr是相同数组的别名,因此通过arr所做的操作(Arrays.sort(arr);)对nums可见,所以会看到nums和arr都进行了排序。而“  int t = arr[i];”是将一个值赋值给一个值,真正做的是创建一个并非引用的“自动”变量,然后赋值。

对象数组和基本数据类型数组在使用上几乎是相同的,唯一区别就是对象数组保存的是引用,基本数据类型直接保存基本类型的值。

知道了为什么出错,那应该怎么改正呢?

先复制数组(复制以后的数组和原数组是不同的对象),然后再操作。可以利用for循环,也可以利用已有的API进行复制。

java.util.Arrays提供了许多方法,以int[]为例:

static int[]

copyOf(int[] original, int newLength)

Copies the specified array, truncating or padding with zeros (if necessary) so the copy has the specified length.

static int[]

copyOfRange(int[] original, int from, int to)

Copies the specified range of the specified array into a new array.

java.lang.System的方法:

static void

arraycopy(Object src, int srcPos,Object dest, int destPos, int length)

Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array.

修改代码,最终可以获得Accept:

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int[] arr = Arrays.copyOf(nums,nums.length);
        Arrays.sort(arr);
        int res =0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]==arr[i]) res++;
            else break;
        }
        if(res==nums.length) return 0;
        for(int i=nums.length-1;i>0;i--){
            if(nums[i]==arr[i]) res++;
            else break;
        }
        return nums.length-res;
    }
}

参考文献:

[1] Bruce Eckel. Java编程思想(第四版)[M]. 陈昊鹏译. 北京:机械工业出版社,2007.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

James Shangguan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值