概述
- 连续存储空间,存相同类型数据的集合
- 二维数组内存空间

二分查找
1.二分查找[704]
- 前提:数组元素有序且不重复
- 时间复杂度:O(logn)
- 注意
left与right边界取值情况
2.搜索插入位置[35]
- 分析

- 暴力解法
时间复杂度:O(n)
------------------------
class Solution {
public int searchInsert(int[] nums, int target) {
for(int i=0;i<nums.length;i++){
if(nums[i]>=target){
return i;
}
}
return nums.length;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int rigth = nums.length-1;
int temp = nums.length;
while(left<=rigth){
int mid = (left+rigth)>>>1;
if(nums[mid]>=target){
temp = mid;
rigth = mid-1;
}else{
left = mid+1;
}
}
return temp;
}
}
---------------------------------------------------
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
int mid = 0;
while(left<=right){
mid = (left+right)>>>1;
if(target>nums[mid]){
left=mid+1;
}else if(target<nums[mid]){
right=mid-1;
}else{
return mid;
}
}
return right+1;
}
}
3.在排序数组中查找元素的第一个和最后一个位置[34]
class Solution {
public int[] searchRange(int[] nums, int target) {
if(nums.length<=0) return new int[]{-1,-1};
int start = -1;
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
start=i;
break;
}
}
if(start==-1) return new int[]{-1,-1};
for(int i=start;i<=nums.length;i++){
if(i==nums.length || nums[i]!=target){
return new int[]{start,i-1};
}
}
return new int[]{-1,-1};
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int left=searchLeft(nums, target);
int right=searchRight(nums, target);
return new int[]{left,right};
}
public int searchLeft(int[] nums, int target){
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
if(mid==0 || nums[mid-1]!=target){
return mid;
}
right = mid-1;
}else if(nums[mid]>target){
right = mid -1;
}else{
left = mid +1;
}
}
return -1;
}
public int searchRight(int[] nums, int target){
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
if(mid==nums.length-1 || nums[mid+1]!=target){
return mid;
}
left = mid+1;
}else if(nums[mid]>target){
right = mid -1;
}else{
left = mid +1;
}
}
return -1;
}
}
---------------------------------------------------
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftOrder=searchLeft(nums, target);
int rightOrder=searchRight(nums, target);
if(leftOrder==-2 || rightOrder==-2) return new int[]{-1,-1};
if(rightOrder-leftOrder>1) return new int[]{leftOrder+1,rightOrder-1};
return new int[]{-1,-1};
}
public int searchLeft(int[] nums, int target){
int left=0;
int right=nums.length-1;
int temp = -2;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]>=target){
right = mid -1;
temp = right;
}else{
left = mid +1;
}
}
return temp;
}
public int searchRight(int[] nums, int target){
int left=0;
int right=nums.length-1;
int temp = -2;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]>target){
right = mid-1;
}else{
left = mid +1;
temp = left;
}
}
return temp;
}
}
4. x的平方根 [69]
- 袖珍计算器算法

利用指数函数与对数函数代替平方根函数
时间复杂度:O(1)
--------------------------------
class Solution {
public int mySqrt(int x) {
int result = (int) Math.exp(0.5*Math.log(x));
return (result+1)*(result+1) == x? result+1:result;
}
}
问题转换:根ans满足k^2<=x,所以对k进行二分查找[0,x],每一步比较mid*mid与x的值
时间复杂度:O(logx)
-----------------------------------------
class Solution {
public int mySqrt(int x) {
int left = 0,right = x,result=-1;
while(left<=right){
int mid = left+(right-left)/2;
if((long)mid*mid<=x){
result=mid;
left=mid+1;
}else{
right=mid-1;
}
}
return result;
}
}
- 牛顿迭代

class Solution {
public int mySqrt(int x) {
if(x==0) return 0;
double x0 = x;
while(true){
double result = 0.5*(x0+x/x0);
if(Math.abs(x0 - result) < 1e-7){
return (int)result;
}
x0=result;
}
}
}
5.有效的完全平方数[367]
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0;
int right = num;
int result = -1;
while(left<=right){
int mid = left+(right-left)/2;
if((long)mid*mid<=num){
result = mid;
left = mid +1;
}else{
right = mid -1;
}
}
return result*result==num?true:false;
}
}
移除元素
1.移除元素[27]
可能是二分法做太多的原因,做啥都像二分法
-------------------------------------------------
class Solution {
public int removeElement(int[] nums, int val) {
Arrays.sort(nums);
int leftOrder = searchLeftOrder(nums,val);
int rightOrder = searchRightOrder(nums,val);
if(leftOrder==-2 || rightOrder==-2) return nums.length;
int vals = rightOrder-leftOrder-1;
if(rightOrder!=nums.length){
for(int i=rightOrder;i<nums.length;i++){
nums[++leftOrder]=nums[i];
}
}
return nums.length-vals;
}
public static int searchLeftOrder(int[] nums,int val){
int left = 0;
int right = nums.length-1;
int leftOrder = -2;
while(left<=right){
int mid = left+(right-left)/2;
if(nums[mid]>=val){
right = mid-1;
leftOrder=right;
}else{
left = mid+1;
}
}
return leftOrder;
}
public static int searchRightOrder(int[] nums,int val){
int left = 0;
int right = nums.length-1;
int rightOrder = -2;
while(left<=right){
int mid = left+(right-left)/2;
if(nums[mid]>val){
right = mid-1;
}else{
left = mid+1;
rightOrder=left;
}
}
return rightOrder;
}
}
class Solution {
public int removeElement(int[] nums, int val) {
int left=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=val){
nums[left]=nums[i];
left++;
}
}
return left;
}
}
class Solution {
public int removeElement(int[] nums, int val) {
int left=0;
int right = nums.length;
while(left<right){
if(nums[left]==val){
nums[left] = nums[right-1];
right--;
}else{
left++;
}
}
return left;
}
}
2.删除有序数组中的重复项[26]
class Solution {
public int removeDuplicates(int[] nums) {
int left = 0;
for(int i=1;i<nums.length;i++){
if(nums[left]!=nums[i]){
left++;
nums[left]=nums[i];
}
}
return left+1;
}
}
3.移动零[283]
class Solution {
public void moveZeroes(int[] nums) {
int left=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=0){
nums[left]=nums[i];
left++;
}
}
for(int i=left;i<nums.length;i++){
nums[i]=0;
}
}
}
4.比较含退格的字符串[844]
class Solution {
public boolean backspaceCompare(String s, String t) {
if(s.equals(t)) return true;
String s1 = backspaceNew(s);
String t1 = backspaceNew(t);
return s1.equals(t1);
}
public static String backspaceNew(String str){
int start=0;
StringBuffer sb = new StringBuffer(str);
while(start<sb.length()){
int index = sb.indexOf("#",start);
if(index==-1){
break;
}
if(index==0){
sb.deleteCharAt(index);
start=index;
continue;
}
sb.delete(index-1,index+1);
start=index-1;
}
return sb.toString();
}
}
class Solution {
public boolean backspaceCompare(String s, String t) {
int i = s.length() - 1, j = t.length() - 1;
int skipS = 0, skipT = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (s.charAt(i) == '#') {
skipS++;
i--;
} else if (skipS > 0) {
skipS--;
i--;
} else {
break;
}
}
while (j >= 0) {
if (t.charAt(j) == '#') {
skipT++;
j--;
} else if (skipT > 0) {
skipT--;
j--;
} else {
break;
}
}
if (i >= 0 && j >= 0) {
if (s.charAt(i) != t.charAt(j)) {
return false;
}
} else {
if (i >= 0 || j >= 0) {
return false;
}
}
i--;
j--;
}
return true;
}
}
5.有序数组的平方[977]
class Solution {
public int[] sortedSquares(int[] nums) {
for(int i=0;i<nums.length;i++){
nums[i] = nums[i]*nums[i];
}
Arrays.sort(nums);
return nums;
}
}
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0;
int rigth = nums.length-1;
int[] numsNew = new int[nums.length];
int index = nums.length-1;
while(left<=rigth){
if(Math.abs(nums[left])<=Math.abs(nums[rigth])){
numsNew[index]=nums[rigth]*nums[rigth];
rigth--;
}else{
numsNew[index]=nums[left]*nums[left];
left++;
}
index--;
}
return numsNew;
}
}
长度最小的子数组
1.长度最小的子数组[209]
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int min=nums.length*2;
int sum=0;
for(int i=0;i<nums.length;i++){
for(int j=i;j<nums.length;j++){
sum+=nums[j];
if(sum>=target){
min=Math.min(min,j-i+1);
break;
}
}
sum=0;
}
return min==nums.length*2?0:min;
}
}
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int start=0,end=0;
int min = nums.length*2;
int sum = 0;
while(end<nums.length){
sum += nums[end];
while(sum>=target){
min=Math.min(end-start+1,min);
sum -= nums[start++];
}
end++;
}
return min==nums.length*2?0:min;
}
}
2.水果成篮[904]
3.最小覆盖子串[76]
螺旋矩阵
1.螺旋矩阵 II[59]
- 模拟旋转过程

class Solution {
public int[][] generateMatrix(int n) {
int [][]matrix = new int[n][n];
int l=0,r=n-1,t=0,b=n-1;
int num = 1;
while(num<=n*n){
for(int i=l;i<=r;i++) matrix[t][i]=num++;
t++;
for(int i=t;i<=b;i++) matrix[i][r]=num++;
r--;
for(int i=r;i>=l;i--) matrix[b][i]=num++;
b--;
for(int i=b;i>=t;i--) matrix[i][l]=num++;
l++;
}
return matrix;
}
}
2.螺旋矩阵[54]
上一题的逆过程,但注意数组边界与循环退出时机
-------------------------------------------
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new ArrayList<Integer>();
int n = matrix.length;
int m = matrix[0].length;
int length = n*m;
int l=0,r=m,t=0,b=n;
while(list.size()<length){
for(int i=l;i<r;i++) list.add(matrix[t][i]);
t++;
if(t==b) break;
for(int i=t;i<b;i++) list.add(matrix[i][r-1]);
r--;
if(r==l) break;
for(int i=r-1;i>=l;i--) list.add(matrix[b-1][i]);
b--;
for(int i=b-1;i>=t;i--) list.add(matrix[i][l]);
l++;
}
return list;
}
}
3.顺时针打印矩阵[剑指29]
注意边界!!!!!
-------------------------------------------
class Solution {
public int[] spiralOrder(int[][] matrix) {
int n = matrix.length;
if(n==0){return new int[0];}
int m = matrix[0].length;
int length = n*m;
int num=0;
int[] array = new int[length];
int l=0,r=m,t=0,b=n;
while(num<length){
for(int i=l;i<r;i++) array[num++]=matrix[t][i];
t++;
if(t==b) break;
for(int i=t;i<b;i++) array[num++]=matrix[i][r-1];
r--;
if(r==l) break;
for(int i=r-1;i>=l;i--) array[num++]=matrix[b-1][i];
b--;
if(t==b) break;
for(int i=b-1;i>=t;i--) array[num++]=matrix[i][l];
l++;
if(r==l) break;
}
return array;
}
}
总结
1.二分法
2.双指针法
- 通过快指针和慢指针在一个for循环下完成两个for循环的工作
3.滑动窗口
4.模拟行为