704. 二分查找
题目要求
思路一 左闭右闭[ ] 突破界限
思路二 左闭右开[ )
思路一
class Solution {
public int search(int[] nums, int target) {
//[l r]
int l = 0;
int r = nums.length - 1;
while(l <= r){
int mid = l + (r - l) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid - 1;
}else{
l = mid + 1;
}
}
return -1;
}
}
思路二
class Solution {
public int search(int[] nums, int target) {
// [l r)
int l = 0;
int r = nums.length;
while(l < r){
int mid = l + (r - l) / 2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid;
}else{
l = mid + 1;
}
}
return -1;
}
}
时间复杂度:O(logn) 证明二分查找的时间复杂度
空间复杂度:O(1)
35. 搜索插入位置
34. 在排序数组中查找元素的第一个和最后一个位置
69. x 的平方根
367. 有效的完全平方数
27. 移除元素
题目要求
思路 重构数组
class Solution {
public int removeElement(int[] nums, int val) {
int index = 0;
for(int i = 0; i < nums.length; i++){
if(nums[i] != val){
nums[index++] = nums[i];
}
}
return index;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
26. 删除有序数组中的重复项
977. 有序数组的平方
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length - 1;
int[] result = new int[nums.length];
int index = result.length - 1;
while(l < r){
if(nums[r] * nums[r] >= nums[l] * nums[l]){
result[index--] = nums[r] * nums[r];
r--;
}else{
result[index--] = nums[l] * nums[l];
l++;
}
}
result[0] = nums[l] * nums[l];
return result;
}
}
时间复杂度:O(n)
空间复杂度:O(n)
88. 合并两个有序数组
283. 移动零
203. 移除链表元素
844. 比较含退格的字符串
977. 有序数组的平方
209. 长度最小的子数组
符合条件的子数组要满足以下的几个条件
target
然后从符合条件的子数组中找出长度最小的子数组,并返回其数组长度
思路一 暴力求解
for
循环确定子数组的左右边界for
用来确定子数组的左边界for
用来确定子数组的右边界注意:
提示中 1 <= nums.length <= 10^5,暴力求解有可能超时。思路二 滑动窗口
窗口,就是满足连续子数组和大于等于target的一个区间
滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果,即长度最小的子数组。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for(int j = 0; j < nums.length; j++){
sum += nums[j];
while(sum >= target){
int len = j - i + 1;
result = len < result ? len : result;
sum -= nums[i++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
904. 水果成篮
76. 最小覆盖子串
718. 最长重复子数组
59. 螺旋矩阵 II
思路一 由外到内 逐圈填充
模拟顺时针画矩阵的过程:
那么要填充多少圈呢?
高度和宽度
都 - 2
思路二 四个守卫,依次抢占领土
上
下
左
右
四个守卫,他们依次循环占领数组的各行或各列,上
下
占领各行,左
右
占领各列上
守卫只能从左到右,依次占领这一行,遇到 右
则停止。停止之后,说明这一行已经被占领,之后从下一行开始。右
守卫只能从上到下,依次占领这一列,遇到 下
则停止。停止之后,说明这一列已经被占领,之后从当前占领的左边开始。下
守卫只能从右到左,依次占领这一行,遇到 左
则停止。停止之后,说明这一行已经被占领,之后从上一行开始。左
守卫只能从下到上,依次占领这一列,遇到 上
则停止。停止之后,说明这一列已经被占领,之后从当前占领的右边开始。思路一
class Solution {
public int[][] generateMatrix(int n) {
int x = 0;
int y = 0;
int i, j;
int count = 1;
int offset = 1;
// 循环圈数 n 为 偶数 则循环圈数正好是整数
int loop = n / 2;
int[][] a = new int[n][n];
while(loop-- > 0){
//左到右
for(j = y; j < n - offset; j++){
a[x][j] = count++;
}
//上到下
for(i = x; i < n - offset; i++){
a[i][j] = count++;
}
//右到左
for(; j > y; j--){
a[i][j] = count++;
}
//下到上
for(; i > x; i--){
a[i][j] = count++;
}
x++;
y++;
offset++;
}
if(n % 2 != 0){
a[x][y] = count;
}
return a;
}
}
思路二
class Solution {
public int[][] generateMatrix(int a) {
int m = a;//m行
int n = a;//n列
int l = 0, r = a - 1;
int low = 0, high = m - 1;
int[][] ans = new int[m][n];
int count = 1;
while(true){
//从左到右
for(int i = l; i <= r; i++) ans[low][i] = count++;
if(++low > high) break;
//从上到下
for(int i = low; i <= high; i++) ans[i][r] = count++;
if(--r < l) break;
//从右到左
for(int i = r; i >= l; i--) ans[high][i] = count++;
if(--high < low) break;
//从下到上
for(int i = high; i >= low; i--) ans[i][l] = count++;
if(++l > r) break;
}
return ans;
}
}
时间复杂度 O(n^2) 模拟遍历二维矩阵的时间
空间复杂度 O(1)
54.螺旋矩阵