剑指 Offer 03. 数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
 [2, 3, 1, 0, 2, 5, 3]
 输出:2 或 3 
class Solution {
    public int findRepeatNumber(int[] nums) {
    }
}解题思路
数组元素的 索引 和 值 是 一对多 的关系。
 因此,可遍历数组并通过交换操作,使元素的 索引 与 值 一一对应(即 nums[i] = i )。因而,就能通过索引映射对应的值,起到与字典等价的作用。
遍历中,第一次遇到数字 x 时,将其交换至索引 x 处;而当第二次遇到数字 x 时,一定有 nums[x]=x ,此时即可得到一组重复数字。
算法流程:
 遍历数组 nums ,设索引初始值为 i = 0 :
若 nums[i] =i : 说明此数字已在对应索引位置,无需交换,因此跳过;
 若 nums[nums[i]] = nums[i] : 代表索引 nums[i]处和索引 i 处的元素值都为nums[i] ,即找到一组重复值,返回此值 nums[i] ;
 否则: 交换索引为 i 和 nums[i] 的元素值,将此数字交换至对应索引位置。
 若遍历完毕尚未返回,则返回 -1 。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 代码如下:
 代码如下:
class Solution {
    public int findRepeatNumber(int[] nums) {
        int i = 0;
        while(i < nums.length) {
            if(nums[i] == i) {
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i]) return nums[i];
            int tmp = nums[i];
            nums[i] = nums[tmp];
            nums[tmp] = tmp;
        }
        return -1;
    }
}剑指 Offer 53. 在排序数组中查找数字
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
 输出: 2
 示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
 输出: 0
class Solution {
    public int search(int[] nums, int target) {
    }
}解题思路

算法解析:
 初始化: 左边界 i = 0 ,右边界 j = len(nums) - 1 。
 循环二分: 当闭区间 [i, j]无元素时跳出;
 计算中点 m = (i + j) / 2(向下取整);
 若 nums[m] < target ,则target 在闭区间[m+1,j] 中,因此执行 i = m + 1;
 若 nums[m] > target ,则 target 在闭区间 [i, m - 1] 中,因此执行 j = m - 1;
 若 nums[m] = target,则右边界right 在闭区间[m+1,j] 中;左边界left 在闭区间 [i,m−1] 中。因此分为以下两种情况:
 若查找 右边界 right ,则执行 i = m + 1;(跳出时 i 指向右边界)
 若查找 左边界 left ,则执行j=m−1 ;(跳出时 j 指向左边界)
 返回值: 应用两次二分,分别查找right 和 left ,最终返回 right - left - 1即可

 
 
 
 
 
 
 
 
 
 
代码如下:
class Solution {
    public int search(int[] nums, int target) {
        // 搜索右边界 right
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= target) i = m + 1;
            else j = m - 1;
        }
        int right = i;
        // 若数组中无 target ,则提前返回
        if(j >= 0 && nums[j] != target) return 0;
        // 搜索左边界 right
        i = 0; j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] < target) i = m + 1;
            else j = m - 1;
        }
        int left = j;
        return right - left - 1;
    }
}以上代码显得比较臃肿(两轮二分查找代码冗余)。为简化代码,可将二分查找右边界 right 的代码 封装至函数 helper() 。 
 
class Solution {
    public int search(int[] nums, int target) {
        return helper(nums, target) - helper(nums, target - 1);
    }
    int helper(int[] nums, int tar) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= tar) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}剑指 Offer 53. 0~n-1 中缺失的数字
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
 输出: 2
 示例 2:
输入: [0,1,2,3,4,5,6,7,9]
 输出: 8
class Solution {
    public int missingNumber(int[] nums) {
    }
}解题思路

算法解析:
 初始化: 左边界 i = 0,右边界j=len(nums)−1 ;代表闭区间[i,j] 。
 循环二分: 当 i≤j 时循环 (即当闭区间 [i,j] 为空时跳出) ;
 计算中点 m=(i+j)/2 ;
 若 nums[m] = m ,则 “右子数组的首位元素” 一定在闭区间[m+1,j] 中,因此执行i=m+1;
 若 nums[m] !=m ,则 “左子数组的末位元素” 一定在闭区间 [i,m−1] 中,因此执行j=m−1;
 返回值: 跳出时,变量 i 和 j 分别指向 “右子数组的首位元素” 和 “左子数组的末位元素” 。因此返回 i 即可。

 
 
 
 
 
 
 
 
 
 
代码如下:
class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] == m) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}














![[附源码]计算机毕业设计springboot智能衣橱APP](https://img-blog.csdnimg.cn/79d76cd5a28e4d47846d25592b854aff.png)




