zoukankan      html  css  js  c++  java
  • LeetCode Notes_#384_打乱数组

    LeetCode Notes_#384_打乱数组

    Contents

    题目


    解答

    方法1: 暴力法

    算法步骤:

    1. array复制到aux数组当中
    2. 每次从aux数组当中随机抽取一个数字,并删除这个数字,直到aux数组为空

    为什么这样做可以保证随机性?

    class Solution {
        private int[] array;
        private int[] original;
        private Random rand = new Random();
    
        private List<Integer> getArrayCopy(){
            List<Integer> asList = new ArrayList<Integer>();
            for(int i = 0;i < array.length;i++){
                asList.add(array[i]);
            }
            return asList;
        }
    
        public Solution(int[] nums) {
            array = nums;
            original = nums.clone();
        }
        
        /** Resets the array to its original configuration and return it. */
        public int[] reset() {
            array = original;
            original = original.clone();
            return array;
        }
        
        /** Returns a random shuffling of the array. */
        public int[] shuffle() {
            List<Integer> aux = getArrayCopy();
            for(int i = 0;i < array.length;i++){
                int removeIdx = rand.nextInt(aux.size());
                array[i] = aux.get(removeIdx);
                aux.remove(removeIdx);
            }
            return array;
        }
    }

    复杂度分析

    时间复杂度:O(n2),auxArrayList类型,每次进行remove()操作的复杂度是O(n),再加上外边的循环,就是O(n2)
    空间复杂度:O(n),复制了一份原数组到auxoriginal

    方法2: Fisher-Yates洗牌算法

    算法步骤:
    遍历数组array当中的每个数字,每次随机选出这个数字之后的一个其他数字与其交换。
    这样做的原理和方法1是类似的,不同的是,使用了交换的方式,避免了remove带来的O(n)的复杂度。

    class Solution {
        //array是每次调用shuffle()就会发生变化的数组
        int[] array;
        //original是在构造器中将原始数组存了下来,在reset()时将array恢复到和original相同
        int[] original;
        Random random = new Random();
    
        public Solution(int[] nums) {
            array = nums;
            //这里是深拷贝一个nums数组,而不能简单的使用 original = nums 
            //原因: array和original如果指向了同一个nums内存空间,之后对nums进行修改的时候,也会影响到original
            original = nums.clone();
        }
    
        //生成范围在[i,array.length - 1]范围内的一个随机整数作为下标
        private int randRange(int min, int max){
            return min + random.nextInt(max - min);
        }
    
        private void swap(int i, int j){
            int tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
        }
        
        /** Resets the array to its original configuration and return it. */
        public int[] reset() {
            //将原始数组拷贝一份,然后让array指向新的拷贝数组
            array = original.clone();
            return array;
        }
        
        /** Returns a random shuffling of the array. */
        public int[] shuffle() {
            for(int i = 0;i <= array.length - 1;i++){
                //注意:nextInt返回值是<array.length,即最大为array.length - 1
                int randIdx = randRange(i, array.length);
                swap(i, randIdx);
            }
            return array;
        }
    }

    复杂度分析

    时间复杂度:O(n)
    空间复杂度:O(n)

    关于java中的clone()方法

    本题有2个考点:

    1. 如何随机打乱,使得每种排列随机出现
    2. java当中的数组的clone方法的理解
      • 如果数组元素是基本类型,不存在浅拷贝,会直接创建新的一个数组,可以理解为深拷贝
      • 如果数组元素是类对象,其实数组保存的是对象的引用,这时clone拷贝的是数组里的那些引用变量,新的引用变量和旧的引用变量指向的是同一个内存空间,修改了一个,另一个也会跟着改变,可以理解为是浅拷贝

    本题当中涉及到clone的数组元素类型都是基本类型int,所以都可以看作是深拷贝,clone会新开辟一片内存空间,保存新的数组,新旧数组不会互相影响。

  • 相关阅读:
    c++ -- c风格字符串,以及c++通过c_str()方法与c风格字符串的转换
    python--sklearn,聚类结果可视化工具TSNE
    ml--分类与预测算法评价方法
    python--pandas学习,依赖库xlrd和xlwt
    python--源码位置查找
    mysql中的group by,having,order by,where用法
    mysql外连接的总结
    mysql数据库中多表关联查询的实例
    理解mysql数据库的事务特征,事务隔离级别,加锁机制
    理解springMVC的controller
  • 原文地址:https://www.cnblogs.com/Howfars/p/13906460.html
Copyright © 2011-2022 走看看