• 循环排序总结


    可以用来处理数组中的数值限定在一定的区间的问题。

    例题:

    1.找到所有数组中消失的数字

    (https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/)

    给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。

    找到所有在 [1, n] 范围之间没有出现在数组中的数字。

    您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

    题本身不难,使用哈希表很容易通过,但如果不使用额外空间和时间复杂度为O(n)时,就比较难了

    思路:我们可以将数组中的每个数根据索引的大小,将对应索引的值都加上n,那么到最后,只有缺少的值对应的索引位置上的值没有加上n,再遍历一遍数组就可以得到缺少的值

    class Solution {
    public:
        vector<int> findDisappearedNumbers(vector<int>& nums) {
            vector<int> ans;
            int n = nums.size();
            for(int i=0;i<n;i++){
                int pos = (nums[i]-1)%n;
                nums[pos] += n; 
            }
            for(int i=0;i<n;i++){
                if(nums[i]<=n){
                    ans.push_back(i+1);
                }
            }
            return ans;
        }
    };
    

    2.寻找重复数

    (https://leetcode-cn.com/problems/find-the-duplicate-number/)

    给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。

    假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。

    同样也可以使用哈希表解决,但有几种巧妙的方法

    (1)二分

    二分法的思路是取[left,right]的中间值mid,然后统计于是数组中 小于等于 mid的个数cnt,如果cnt的个数严格大于mid,那么答案就在[left,mid]中

    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size();
            int l = 1,r = n-1;
            while(l<r){
                int mid = (l+r)/2;
                int cnt = 0;
                for(int i=0;i<n;i++){
                    cnt += (nums[i] <= mid);
                }
                //抽屉原理,如果小于等于mid的个数大于4,那么重复元素一定存在于[1,4]
                if(cnt > mid) r = mid;
                else l = mid + 1;
            }
            return l;
        }
    };
    

    (2)位运算

    位运算的思路是,先统计数组中每个元素在每一位上的个数x,然后统计[1,n]中每个元素在每一位上的个数y,如果x大于y,那么重复元素在该位是有值的。

    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int n = nums.size();
            int bit_max = 31;
            while(!((n-1) >> bit_max)){ //得到数组中数的最高位
                bit_max--;
            }
            int ans = 0;
            for(int i = 0 ;i <= bit_max;i++){
                int x = 0,y = 0;
                for(int j = 0;j < n;j++){
                    if(nums[j] & (1 << i)){
                        x++;
                    }
                    if(j && (j & (1 << i))){
                        y++;
                    }
                }
                //对存在的位进行或运算
                if(x > y){
                    ans |= (1<<i);
                }
            }
            return ans;
        }
    };
    

    (3)快慢指针

    如果数组中存在重复的元素,那么指针根据nums[]对应的索引来移动,那么最后一定会进入环中。不懂快慢指针的可以看前几天的题解。

    快慢指针时间复杂度O(n),空间复杂度O(1).

    class Solution {
    public:
        int findDuplicate(vector<int>& nums) {
            int fast = 0,slow = 0;
            do{
                slow = nums[slow];
                fast = nums[nums[fast]];
            }while(fast != slow);
            slow = 0;
            while(slow != fast){
                slow = nums[slow];
                fast = nums[fast];
            }
            return slow;
        }
    };
    
    七月在野,八月在宇,九月在户,十月蟋蟀入我床下
  • 相关阅读:
    golang strings.Split函数
    Launch agent by connecting it to the master
    使用srvany.exe把程序安装成windows服务的方法
    区别对待 .gz 文件 和 .tar.gz 文件
    go 使用 sort 对切片进行排序
    Go数组遍历与排序
    Container killed on request. Exit code is 143
    ERROR tool.ImportTool
    报错笔记:sqoop 执行import命令报错
    连不上网
  • 原文地址:https://www.cnblogs.com/voids5/p/14372166.html
Copyright © 2020-2023  润新知