LeedCode习题集

1.题目:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.

说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
难度:简单

思路:
1·可以考虑使用暴力解法,写两个for循环,i从0开始遍历到数组length,第二个循环j从0开始遍历。

	public int singleNumber(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            int flag = i;
            for (int j = 0; j < nums.length; j++) {
                if (nums[i] == nums[j] && i != j) {
                    flag = -1;
                    break;
                }
            }
            if (flag != -1) return nums[flag];
        }
        return 0;
    }

时间复杂度O(n^2),空间复杂度O(1)
在这里插入图片描述

2·考虑到每个元素都只出现一次或者两次,所以最终结果的和应该为sum=2a+2b+…+n,所以我们只要求得sum1=a+b+c+…+n 用2*sum1-sum就等于没有‘对象’的那个数哈哈

	 public int singleNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
        int sum = 0, sum1 = 0, i = 0;
        while (i < nums.length) {
            set.add(nums[i]);
            sum += nums[i++];
        }
        for (Integer integer : set) {
            sum1 += integer;
        }
        return sum1 * 2 - sum;
    }

在这里插入图片描述
时间复杂度O(n),空间复杂度O(n)
发现两次都没有达到题目的要求,第一个时间复杂度高了,第二使用了n的空间。
然后去评论里面看看大神的答案哈哈,用到了异或.
先来看看异或是什么东东。
若x是二进制数0101,y是二进制数1011;
0101
1011

1110 则x⊕y=1110
不同位取1,同一位取0。可以发现相同的数取异或等于0,任何数与0异或有等于他本身;
所以 a ^ a ^ b = b; a ^ b ^ a = b; b ^ a ^ b = b;

3·这道题可以巧妙的使用异或来完成题目
a异或a异或b异或b异或c异或c异或d=d

	 public int singleNumber(int[] nums) {
        int result = nums[0];
        for (int i = 1; i < nums.length; i++) {
            result ^= nums[i];
        }
        return result;
    }

在这里插入图片描述
拓展:给你一个长度为 n 的数组,其中只有一个数字出现了奇数次,其他均出现偶数次
对于这种要找出特殊值得题目,一般不会使用指针,下次考虑下异或喔!
从这里就可以看出前两种的方法的局限性了,但是第三种还是仍然适用的。
可以看出即使同一个简单的题目,也有很优化的方法,加油!

2.题目:给你一个长度为 n 的数组,其中只有一个数字出现了大于等于 n/2 次,问如何使用优秀的时空复杂度快速找到这个数字。

思路:
1.使用暴力解法,新建一个map,key为数,value为值。最后遍历map找出value最大的数为众数。
初步可以估计出时间复杂度O(n),空间复杂度0(n)

	public int majorityElement(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])) map.put(nums[i], map.get(nums[i]) + 1);
            else map.put(nums[i], 1);
        }
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > nums.length / 2) return entry.getKey();
        }
        return 0;
    }

在这里插入图片描述
因为有个特殊条件(有一个数字出现了大于等于 n/2 次)还没有使用----当然可以在取出value++的是否判断是否大于等于 n/2 提前结束循环,当然并不影响时间复杂度和空间复杂度

看了下评论。
2.其实也又想到过这个问题。就是排好序后,最中间的nums[n/2]必定是我们想要的答案,但是忘记java排序的api了,附上代码,很简洁。

	public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }

在这里插入图片描述
当然效果也还是一般咯。
3.第三个方法就比较巧妙了:先假设result是第一个数,然后从第二个数开始遍历,遇见相同的就+1,不同的就-1,如果count==0,就result赋值为下一个数,接着遍历,最后result的值 就是结果。该方法的思想是众数一定比其他所有的数加起来的数量要多,就算是众数与其他每一个数相抵消,最后剩下来的也是众数。况且还有其他数之间的抵消,所以剩下来的一定是众数。

	int count = 1;
        int result = nums[0];
        for (int i = 1; i < nums.length; i++) {
            count = result == nums[i] ? ++count : --count;
            if (count == 0) {
                result = nums[i+1];
            }
        }
        return result;

在这里插入图片描述

3.编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。

该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。

思路:
1.要从最小的数开始遍历,左上角的数。开始遍历,当该行的当前数>target开始下一行,代码很简单:

	public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix.length == 0 || matrix[0].length == 0) return false;
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                if (matrix[i][j] == target) return true;
                if (matrix[i][j] > target) break;
            }
        }
        return false;
    }

时间复杂度O(n^2),空间复杂度O(0)
结果
2.在刚才的代码中继续优化,我们上一段代码只用到从左到右的递增,还没用到从上到校的递增。比如我们到了第i行的第j列已经大于我target了,毫无疑问第i+1行第j列也必定大于target。

	public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix.length == 0 || matrix[0].length == 0) return false;
        int right = matrix[0].length;
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < right; j++) {
                if (matrix[i][j] == target) return true;
                if (matrix[i][j] > target) {
                    right = j;
                    break;
                }
            }
        }
        return false;
    }

时间复杂度O(n^2),空间复杂度O(0)
在这里插入图片描述
哈哈哈还不如刚才了,我发现内存比上一次还大,那就继续修改代码试试。
3.使用递归是万万不可能的,因为递归对内存消耗更大。栈帧会不断进入虚拟机栈,直到第一个栈帧出栈。我们试试能不能制定一个规则:遇到a[i][j]>target时要么i++,j–,a[i][j]<target时j++,a[i][j]=target就跳出循环break;
看了看评论:发现还是思路不对

分治法。
左下角的元素是这一行中最小的元素,同时又是这一列中最大的元素。比较左下角元素和目标:
若左下角元素等于目标,则找到
若左下角元素大于目标,则目标不可能存在于当前矩阵的最后一行,问题规模可以减小为在去掉最后一行的子矩阵中寻找目标
若左下角元素小于目标,则目标不可能存在于当前矩阵的第一列,问题规模可以减小为在去掉第一列的子矩阵中寻找目标
若最后矩阵减小为空,则说明不存在

我的理解是找到一个临界分界点,向左或向右接近答案,下午搜搜分治法是什么东东。感觉也很巧妙这个解法,总是能找到一个该向上或先右的规则。真是笨奥哈哈。
target>a[i][j] j++
target<a[i][j] i–
说实话我还是对这个能遍历到所有元素怀疑

	public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix.length == 0 || matrix[0].length == 0) return false;
        int i = matrix.length - 1;
        int j = 0;
        while (i >= 0 && j < matrix[0].length) {
            if (matrix[i][j] < target) j++;
            else if (matrix[i][j] > target) i--;
            else return true;
        }
        return false;
    }

在这里插入图片描述
哈哈哈打扰了,还有更好的办法!!!
看了下评论代码都差不多,我试试他的是多少…

	public boolean searchMatrix(int[][] matrix, int target){
        if (matrix.length==0)
            return false;
        int i = matrix.length-1,j=0;
        while(i>=0 && j<matrix[0].length){
            if (matrix[i][j] == target)
                return true;
            else if(matrix[i][j]>target)
                i--;
            else if(matrix[i][j]<target)
                j++;
        }
        return false;
    }

在这里插入图片描述
说起来就比我快了1ms差距就这么大吗,我看看我的代码可以改改哪?

	public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix.length==0) return false;
        int i = matrix.length - 1;
        int j = 0;
        while (i >= 0 && j < matrix[0].length) {
            if (matrix[i][j] < target) j++;
            else if (matrix[i][j] > target) i--;
            else if (matrix[i][j] == target) return true;
        }
        return false;
    }

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值