剑指offer刷题笔记day1

03 数组中重复的数字

题目:找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3

限制:

2 <= n <= 100000

我自己本身想的可以输出2或3(也就是每个重复的数字都有输出的机会)是通过一次遍历建立HashMap键值对,如果有重复的值那么就放到存储重复数字的list中,最后通过random函数随机返回一个重复的数,但是这样做时间超了

官方的解法:
方法一:遍历数组

由于只需要找出数组中任意一个重复的数字,因此遍历数组,遇到重复的数字即返回。为了判断一个数字是否重复遇到,使用集合存储已经遇到的数字,如果遇到的一个数字已经在集合中,则当前的数字是重复数字。

初始化集合为空集合,重复的数字 repeat = -1
遍历数组中的每个元素:
    将该元素加入集合中,判断是否添加成功
        如果添加失败,说明该元素已经在集合中,因此该元素是重复元素,将该元素的值赋给 repeat,并结束遍历
返回 repeat
class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        int repeat = -1;
        for (int num : nums) {
            if (!set.add(num)) {
                repeat = num;
                break;
            }
        }
        return repeat;
    }
}

复杂性分析

时间复杂度:O(n)
    遍历数组一遍。使用哈希集合(HashSet),添加元素的时间复杂度为 O(1),故总的时间复杂度是 O(n)O(n)O(n)。
空间复杂度:O(n)。不重复的每个元素都可能存入集合,因此占用 O(n)额外空间。

cyc的解法
(这里的要求是时间复杂度为o(n),空间复杂度为o(1),虽然我没有在题目中看到这个要求…)因此不能使用排序的方法,也不能使用额外的标记数组
对于这种数组在[0,n-1]范围内的问题,可以将值为i的元素调整到第i个位置上进行求解。本题要求找出重复的数字,因此在调整过程中,如果第i位置上已经有一个值为i的元素,就可以知道i值重复。
剑指offer刷题笔记day1_第1张图片
根据cyc的思路我自己的代码(感觉和他说的不那么一样但是也能做出来)

public int findRepeatNumber(int[] nums) {

        for (int i=0;i<nums.length;i++){
            if (nums[i]!=i&&nums[i]>=i){
                change(i,nums[i],nums);
            }
            if (nums[nums[i]]==nums[i]&&i!=nums[i])
                return nums[i];
        }
        return -1;
    }
     public static void change(int i,int j,int[] nums){//交换数组中i和j的位置
        int t=nums[i];
        nums[i]=nums[j];
        nums[j]=t;
    }

剑指offer刷题笔记day1_第2张图片
cyc的代码:

public boolean duplicate(int[] nums, int length, int[] duplication) {
    if (nums == null || length <= 0)
        return false;
    for (int i = 0; i < length; i++) {
        while (nums[i] != i) {
            if (nums[i] == nums[nums[i]]) {
                duplication[0] = nums[i];
                return true;
            }
            swap(nums, i, nums[i]);
        }
    }
    return false;
}

private void swap(int[] nums, int i, int j) {
    int t = nums[i];
    nums[i] = nums[j];
    nums[j] = t;
}

我好像没有判断数组为0的时候的情况哦
看网友们讨论面试官会给出时间复杂度和空间复杂度的要求,这个要根据情况来选择方法了
还有一种非常简单的方法(直接排序,然后判断相邻位置是否相等,若有则存在重复的元素返回即可)但这样时间复杂度要高些

 public int findRepeatNumber(int[] nums) {
        Arrays.sort(nums);
        for (int i=1; i<nums.length; i++) {
            if (nums[i] == nums[i - 1]) {
                return nums[i];
            }
        }
        return nums[0];
    }

剑指offer刷题笔记day1_第3张图片
题解参考:https://www.nowcoder.com/questionTerminal/623a5ac0ea5b4e5f95552655361ae0a8?answerType=1&f=discussion

04 二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

示例:

现有矩阵 matrix 如下:

[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]

给定 target = 5,返回 true。

给定 target = 20,返回 false。

限制:

0 <= n <= 1000

0 <= m <= 1000

很简单,一次过,思路跟C不大一样,他是从右上角开始我是从左上角开始

 public boolean findNumberIn2DArray(int[][] matrix, int target) {
    boolean r=false;
        for (int i = 0; i <matrix.length ; i++) {
            for (int j = 0; j <matrix[0].length ; j++) {
                if (matrix[i][j]>target)
                    continue;
                else if (matrix[i][j]==target){
                    r=true;
                }
            }

        }
        return r;
    }

这里也贴下C的思路(感觉逻辑性更好一些):
要求时间复杂度o(m+n),空间复杂度o(1)其中m为行数,n为列数
该二维数组中的一个数,小于它的数一定在其左边,大于他的数一定在其下边。因此,从右上角开始查找,就可以根据target和当前元素的大小关系来缩小查找的区间,当前元素的查找区间为左下角的所有元素。
代码:

public static boolean find(int[][] matrix,int target){
        if (matrix==null||matrix.length==0||matrix[0].length==0)
            return false;
        int rows=matrix.length;
        int cols=matrix[0].length;
        int r=0,c=cols-1;//从右上角开始
        while (r<=rows-1&&c>=0){
            if (matrix[r][c]==target)
                return true;
            else if (matrix[r][c]>target)
                c--;
            else
                r++;
        }
        return false;
    }

剑指offer刷题笔记day1_第4张图片(是比我写的强)

你可能感兴趣的:(leetcode)