array-用下标来标记index-as-mark

刚刚写了bucket sort,就是利用下标来排序。而这里的一些问题,是用下标来实现别的功能的,比如“标记”,标记某个元素是否出现过。

注意一个区别,这类问题是:利用“下标”来记录“元素值本身”,而不是利用“下标”来记录“下标”(参考73.Set Matrix Zeroes,我原来以为73属于这一类其实不是)。

题目简介
442. Find All Duplicates in an Arrayindex-as-mark
448. Find All Numbers Disappeared in an Arrayindex-as-mark
41. First Missing Positivecyclic swapping
765. Couples Holding Handscyclic swapping(另外一篇写)

442和448是使用下标标记,需要原数组有一个特性,比如“都大于零”,或者比如“都在-10~10范围内”。这样“标记”操作可以用“取负数”,或者“乘以11”来实现,被标记的元素可以完全和原来元素区别开来。

41和765都是cyclic swapping。41其实也是利用下标来交换元素,然而41和765被分类为一个神奇方法,于是另外开一篇写。

442. Find All Duplicates in an Array

一个数组,每个元素1 ≤ a[i] ≤ n (n = size of array), 有些出现两次,有些一次。求在 [1, n] 范围内哪些数没有再数组中出现。
Input:[4,3,2,7,8,2,3,1],Output:[2,3]

把每个数在“正数数列”中应该在的下标处的数翻转(取负数),不关心那个位置上的数本身的值,只是借用哪个下标而已。然而也不是完全不关心啦,在翻转之前先看看它是否已经被翻转过,如果已经被翻转过,则,bingo!找到一个duplicate!

原数组:[4,3,2,7,8,2,3,1]
正数数列:[1,2,3,4,5,6,7,8]

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        // when find a number i, flip the number at position i-1 to negative. 
        // if the number at position i-1 is already negative, i is the number that occurs twice.
        List<Integer> res = new ArrayList<>();
        for (int i = 0; i < nums.length; ++i) {
            int index = Math.abs(nums[i]) - 1;//在正数数列中要翻转的下标
            if (nums[index] < 0) {//之前标记过(这是第二次出现)
                res.add(Math.abs(index + 1));
            }
            nums[index] = -nums[index];//翻转    
        }
        return res;
    }
}

448. Find All Numbers Disappeared in an Array

一个数组,每个元素1 ≤ a[i] ≤ n (n = size of array), 有些出现两次,有些一次。求在 [1, n] 范围内哪些数没有再数组中出现。
Input:[4,3,2,7,8,2,3,1],Output:[5,6]

基本思路和442一样,唯一区别是不能在第一遍扫的过程中就确定哪个disappear,而是要全扫完之后再来一遍,找到没被标记过的。

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < nums.length; ++i) {
            int index = Math.abs(nums[i]) - 1;
            if (nums[index] > 0) {
                nums[index] = -nums[index];
            }
        }
        for (int i = 0; i < nums.length; ++i) {
            if (nums[i] > 0) {
                result.add(i + 1);
            }
        }
        return result;
    }
}

41. First Missing Positive

Input: [3,4,-1,1] Output: 2。找到第一个缺失的正数。

举个🌰:
nums = [3,4,-1,1] -->现有的数组
nums = [1,2,3,4] -->连续正数数组

cyclic swapping的过程:

  • i=0,nums[0]的数3不在正确的位置上,应该换到它应该待的位置:nums[2],[-1,4,3,1] ,换过来的新的-1不是正数,于是i++
  • i=1,nums[1]的数4不在正确的位置上,应该换到它应该待的位置:nums[3],[-1,1,3,4] ,换过来的新数1是正数,且不在正确的位置上,于是i并不自增,下一轮还是i=1
  • i=1, nums[1]的数1不在正确的位置上,应该换到它应该待的位置:nums[0],[1,-1,3,4] ,换过来的新的-1不是正数,于是i++
  • i=2,nums[2]的数在正确的位置上
  • i=3,nums[3]的数在正确的位置上。结束。

为什么这个过程可以保证不漏掉任何一位呢?因为我们的i是一位一位往后捋的,一定要保证当前位置的值或者1)是负数,或者2)在正确的位置上,否者不会i++的。

class Solution {
    public int firstMissingPositive(int[] nums) {
        int len = nums.length;
        //swap each num to its correct position
        for (int i = 0; i < len; i++) {
            while (nums[i] >= 1 && nums[i] <= len && nums[nums[i]-1] != nums[i]) { 
                //swap nums[i] <==> nums[nums[i]-1]
                int temp = nums[nums[i]-1]; //save nums[nums[i]-1] first!!
                nums[nums[i]-1] = nums[i];
                nums[i] = temp;
            }
        }
        //check first missing num
        for (int i = 0; i < len; i++) {
            if (nums[i] != i+1) {
                return i+1;
            }
        }
        return len + 1;
    }
}

765. Couples Holding Hands

Input: row = [0, 2, 1, 3],Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person. 我们认为(0,1),(2,3),…是couple,求最少的swap使得每对couple都挨着。

本来我觉得41.first missing positive和前面442,448类似,都是用下标来标记,或者找与当前值val相对应的下标nums[val-1]的那个元素进行交换。总之我感觉差不多。

这个题765和41都被归类为cyclic swapping,貌似还挺复杂的,(为啥41这么简单呵呵)于是决定另外开一篇单独写cyclic swapping好啦。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值