一、数组类算法
- 数组下标都是从0开始的;数组内存空间的地址是连续的
- 数组的元素是不能删的,只能覆盖
c++中的二维数组在地址空间上是连续的,Java中二维数组程序员无法看到真实地址,每一行头节点的地址是没有规则的
1、(704)二分查找
坚持根据查找区间的定义来做区间边界处理,区间的定义就是不变量,循环不变量原则当题目的前提是有序数组且无重复元素,则可以考虑使用二分法
(1)如果有区间是左闭右闭,即[left,right]
public static int search(int[] nums, int target) {
int size = nums.length;
int med;
int i = 0, j = size-1;
while (i<=j){ // 当left==right,区间[left, right]依然有效,所以用 <=
//med = (i+j)/2; //要注意每次循环改变med的值;为了避免i+j会溢出,采用 i+(j-1)/2
med = i+(j-i)/2;
if (target == nums[med]){
break;
}else if (target < nums[med]){
j = med-1;
}else {
i = med+1;
};
}
return -1;
}
(2)如果区间是左闭右开,即[left,fight)
注意每一次确定meddle的位置,要右移一位
int middle = left + ((right - left) >> 1);
2、(27)移除元素
巧用双指针思想:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
public static int removeElement1(int[] nums, int val) {
int len = nums.length;
int i = 0;
for (int x:nums) {
if (x == val)
len--;
else
nums[i++] = x;
}
return len;
}
3、(977)有序数组的平方
(1)暴力法:冒泡两个for循环
注意两个for循环的限定范围
public static int[] sortedSquares1(int[] nums) {
int m,n;
int temp;
for(int i=0;i<nums.length;i++){
nums[i] = nums[i]*nums[i];
}
for (m=0;m<nums.length-1;m++)
for (n=0;n<nums.length-m-1;n++)
if (nums[n]>nums[n+1]){
temp = nums[n];
nums[n] = nums[n+1];
nums[n+1] = temp;
}
return nums;
}
(2)双指针法
因为初始数组是有序的,所以平房之后最大的数只可能出现在数组的两头,用两个指针对两头的数组元素进行比较,选择大的尾插一个新的数组即可
ps:偶然发现debug用来调试数组算法的错误,真是不要太舒服,善用debug
public static int[] sortedSquares2(int[] nums){
int[] temp;
int k=nums.length-1,i=0,j=nums.length-1;
temp = new int[k+1];
while (i != j){
if (nums[i]*nums[i] > nums[j]*nums[j]){
temp[k--] = nums[i]*nums[i];
++i;
}else {
temp[k--] = nums[j]*nums[j];
--j;
}
}
temp[k] = nums[j]*nums[j];
return temp;
}
4、(209)长度最小的子数组
(1)暴力法:直接两个for循环,即可遍历所有长度的子数组情况;
public static int minSubArrayLen1(int target, int[] nums) {
int result_len = 10000; //最终的当前最短子数组长度
int sum; //子数组的和
int len; //每次记录的当前最短子数组长度
for (int i=0;i<nums.length;i++) {
sum = 0;
for (int j=i;j<nums.length;j++){
sum += nums[j];
if (sum >= target){
len = j-i+1;
result_len = result_len<len?result_len:len; //每次更新最短子数组的长度
break;
}
}
}
if (result_len > nums.length)
return 0;
else
return result_len;
}
(2)滑动窗口法:
public static int minSubArrayLen2(int target, int[] nums){
int result = Integer.MAX_VALUE; //最终的当前最短子数组长度
int sum = 0; //子数组的和
int len = 0; //每次记录的当前最短子数组长度
int i = 0; //滑动窗口的起始位置
for (int j=0;j<nums.length;j++){ //滑动窗口的终止位置
sum += nums[j];
while (sum >= target){
len = (j-i)+1;
result = result<len ? result:len; //每次更新最短子数组的长度
sum -= nums[i++];
}
}
return result == Integer.MAX_VALUE ? 0:result;
}
5、(59)螺旋矩阵 II
坚持循环不变量原则,模拟顺时针画矩阵的过程,从左上到右上,从右上到右下,从右下到左下,从左下到左上。(范围界定保持一致)
要注意画每条边的时候,要注意保持长度一致;另外注意奇数和偶数n的区别
public static int[][] generateMatrix(int n) {
int res[][] = new int[n][n]; //定义一个二维数组
int startx = 0,starty = 0; //循环的起始位置
int loop = n/2; //循环的圈数
int mid = n/2; //矩阵最中间的值
int count = 1; //每个方格赋值数据
int offset = 1; //每循环一圈 控制每条边的长度
int i,j; //控制for循环的变量
while ((loop--) > 0){
i = startx;
j = starty;
//从左上到右上
for (;j < n+starty-offset;j++){
res[i][j] = count++;
}
//从右上到右下
for (;i < n+startx-offset;i++){
res[i][j] = count++;
}
//从右下到左下
for (;j > starty;j--){
res[i][j] = count++;
}
//从左下到左上
for (;i > startx;i--){
res[i][j] = count++;
}
//第二圈从(1,1)开始 循环罔替
++startx;
++starty;
//更新第二圈以后的边长控制变量,因为前一次循环每条边都用去了两个方格
offset += 2;
}
//如果n为奇数,则最中间只有一个数字
if (n%2 == 1){
res[mid][mid] = count;
}
return res;
}
刷题顺序按照代码随想录推荐
其他算法题解,敬请期待!
只为记录自己刷题过程,有问题欢迎探讨!