剑指 Offer 53 - II. 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) {
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;
}
}
剑指 Offer 53 - I. 在排序数组中查找数字 I
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
算法解析:
初始化: 左边界 i = 0,右边界 j=len(nums)−1 。
循环二分: 当闭区间 [i, j] 无元素时跳出;
计算中点 m = (i + j) / 2 (向下取整);
若 nums[m] < target,则 target 在闭区间 [m+1,j] 中,因此执行 i = m + 1i;
若 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;
}
}
LeetCode35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
class Solution {
public int searchInsert(int[] nums, int target) {
/*
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid]>target){
right=mid-1;
}else{
left=mid+1;
}
}
return left;
*/
for(int i=0;i<nums.length;i++){
if(target<=nums[i]){
return i;
}
}
return nums.length;
}
}
LeetCode167. 两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
class Solution {
public int[] twoSum(int[] numbers, int target) {
if (numbers == null) return null;
int i = 0, j = numbers.length - 1;
while (i < j) {
int sum = numbers[i] + numbers[j];
if (sum == target) {
return new int[]{i + 1, j + 1};
} else if (sum < target) {
i++;
} else {
j--;
}
}
return null;
}
}
LeetCode209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
class Solution {
public int minSubArrayLen(int s, int[] nums) {
int start=0;
int end=0;
int sum=0;
int min=Integer.MAX_VALUE;
while(end<nums.length){
sum+=nums[end];
end++;
while(sum>=s){
min=Math.min(min,end-start);
sum-=nums[start];
start++;
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
}
/*
public int minSubArrayLen(int s, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int left = 0;
int right = 0;
int sum = 0;
int min = Integer.MAX_VALUE;
while (right < n) {
sum += nums[right];
right++;
while (sum >= s) {
min = Math.min(min, right - left);
sum -= nums[left];
left++;
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
LeetCode1337. 方阵中战斗力最弱的 K 行
给你一个大小为 m * n 的方阵 mat,方阵由若干军人和平民组成,分别用 1 和 0 表示。
请你返回方阵中战斗力最弱的 k 行的索引,按从最弱到最强排序。
如果第 i 行的军人数量少于第 j 行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。
军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。
示例 1:
输入:mat =
[[1,1,0,0,0],
[1,1,1,1,0],
[1,0,0,0,0],
[1,1,0,0,0],
[1,1,1,1,1]],
k = 3
输出:[2,0,3]
解释:
每行中的军人数目:
行 0 -> 2
行 1 -> 4
行 2 -> 1
行 3 -> 2
行 4 -> 5
从最弱到最强对这些行排序后得到 [2,0,3,1,4]
示例 2:
输入:mat =
[[1,0,0,0],
[1,1,1,1],
[1,0,0,0],
[1,0,0,0]],
k = 2
输出:[0,2]
解释:
每行中的军人数目:
行 0 -> 1
行 1 -> 4
行 2 -> 1
行 3 -> 1
从最弱到最强对这些行排序后得到 [0,2,3,1]
class Solution {
public int[] kWeakestRows(int[][] mat, int k) {
int[][] tmp = new int[mat.length][2];
for(int i = 0; i < mat.length; i++){
for(int j = 0; j < mat[0].length; j++){
tmp[i][0] = i;
if(mat[i][j] == 1) tmp[i][1] += 1;
}
}
Arrays.sort(tmp, (o1, o2) -> o1[1] - o2[1]);
int[] res = new int[k];
for(int i =0; i < k; i++){
res[i] = tmp[i][0];
}
return res;
}
}
LeetCode1351. 统计有序矩阵中的负数
给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。
请你统计并返回 grid 中 负数 的数目。
示例 1:
输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。
示例 2:
输入:grid = [[3,2],[1,0]]
输出:0
示例 3:
输入:grid = [[1,-1],[-1,-1]]
输出:3
示例 4:
输入:grid = [[-1]]
输出:1
class Solution {
public int countNegatives(int[][] grid) {
int cnt = 0;
for(int i=0;i<grid.length;i++){
//按列非递增
if(grid[i][0]<0){
cnt += (grid.length-i)*grid[0].length;
break;
}
for(int j=0;j<grid[i].length;j++){
//按行非递增
if(grid[i][j]<0){
cnt += grid[i].length-j;
break;
}
}
}
return cnt;
}
}