• 【LeetCode-数组】有序数组中的单一元素


    题目描述

    给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
    示例:

    输入: [1,1,2,3,3,4,4,8,8]
    输出: 2
    
    输入: [3,3,7,7,10,11,11]
    输出: 10
    

    注意:
    您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。

    题目链接: https://leetcode-cn.com/problems/single-element-in-a-sorted-array/

    思路1

    将数组中的值进行异或,最终的结果就是只出现一次的数字。

    class Solution {
    public:
        int singleNonDuplicate(vector<int>& nums) {
            int ans = nums[0];
            for(int i=1; i<nums.size(); i++){
                ans ^= nums[i];
            }
            return ans;
        }
    };
    

    这种思路没有用到数组有序这个条件,而且时间复杂度为 O(n),不是题目要求的 O(log n)。

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

    思路2

    题目要求时间复杂度为 O(log n),这就在暗示我们使用二分查找来做。二分查找的关键点就是如何更新 left 和 right。假设当前查找的范围为 [left, right],mid = (left+right)/2。如果 mid 为偶数,则说明 mid 前面有偶数个数,例如 mid = 2,则 mid 前面有 2 个数(下标为 0, 1);如果 mid 为奇数,则说明 mid 前面有奇数个数。

    如果 mid 为偶数,则 mid 前面有偶数个数,我们判断 nums[mid] 和 nums[mid+1] 是否相等。

    • 如果两者相等,则说明前面偶数个数字都是出现两次的数字。例如,数组为 [1,1,2,2,3],mid == 2 为偶数,nums[mid]==nums[mid+1]==2,所以 mid 前面的偶数个数字都出现了两次(两个 1),则出现一次的数字在 mid 右边,此时我们更新 left = mid + 1;
    • 否则,如果 nums[mid] 和 nums[mid+1] 不相等,则出现一次的数字在 mid 左边,此时更新 right = mid - 1。例如,数组为 [1,2,2,3,3],mid == 2,nums[mid]!=nums[mid+1], 1 在 mid 左边。

    如果 mid 为奇数,则 mid 前面有奇数个数,我们同样判断 nums[mid] 和 nums[mid+1] 是否相等。

    • 如果两者相等,则说明只出现一次的数在 mid 左边,更新 right = mid - 1。例如,数组为 [1,2,2,3,3,4,4],mid == 3 为奇数,nums[mid]==nums[mid+1],所以 1 在 mid 左边。
    • 否则,如果两者不等,则说明只出现一次的数在 mid 右边,更新 left = mid + 1。例如,数组为 [1,1,2,2,3,3,4],mid==3,nums[mid]!=nums[mid+1],所以 4 在 mid 右边。

    总结一下:

    • 首先判断 mid 的奇偶性,通过 mid 的奇偶性可以知道 mid 前有奇数个元素还是偶数个元素,然后通过 nums[mid] 和 nums[mid+1] 是否相等来缩小查找范围。
    • 如果 mid 为偶数:
      • 判断 nums[mid] 和 nums[mid+1] 是否相等:
        • 相等,则更新 left = mid + 1;
        • 不等,则更新 right = mid - 1;
    • 如果 mid 为奇数:
      • 判断 nums[mid] 和 nums[mid+1] 是否相等:
        • 相等,则更新 right = mid - 1;
        • 不等,则更新 left = mid + 1;

    代码如下:

    class Solution {
    public:
        int singleNonDuplicate(vector<int>& nums) {
            int left = 0;
            int right = nums.size()-1;
            while(left<=right){
                int mid = left+(right-left)/2;
                if(mid%2==0 && mid+1<nums.size()){ // mid 为偶数
                    if(nums[mid]==nums[mid+1]) left = mid+1;   // nums[mid]==nums[mid+1]
                    else right = mid-1;
                }else if(mid%2!=0 && mid+1<nums.size()){  // mid 为奇数
                    if(nums[mid]==nums[mid+1]) right = mid-1;  // nums[mid]==nums[mid+1]
                    else left = mid+1;
                }else return nums[mid];  // 注意这一步说明 mid 为最后一个元素
            }
            return nums[left];  // 最后返回 nums[left]
        }
    };
    
    • 时间复杂度:O(logn)
    • 空间复杂度:O(1)

    参考

    https://leetcode-cn.com/problems/single-element-in-a-sorted-array/solution/python3-qing-xi-si-lu-yong-shi-ji-bai-97nei-cun-ji/

  • 相关阅读:
    reflow和repaint
    移动端事件
    不支持冒泡的事件
    Gulp
    JAVAWEB项目Tomcat与内网穿透实现外网访问,可连接mysql数据库
    Echarts连接Mysql使用心得
    layui的date组件在弹窗里闪退的解决办法
    Layui的table标签使用记录
    Layui后台实现页面内部的iframe跳转
    第16周作业
  • 原文地址:https://www.cnblogs.com/flix/p/13568355.html
Copyright © 2020-2023  润新知