一.数组
1.lc 27移除数组中的重复元素
且必须仅使用 O(1)
额外空间并 原地 修改输入数组。
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案
public static int removeElement(int[] nums, int val) {int i = 0;int len = nums.length;while (i<len){if (nums[i]==val){nums[i] = nums[len-1];len--;}else {i++;}}return len;}
总结:直接输出移除指定元素后的数组长度是非常容易的,原地修改数组需要:如果第一个元素是指定的元素,那么我们将最后一个元素的值赋给第一个元素并且len指针往前移(逻辑上把指定元素删了,数组长度减1)。
2.lc977 有序数组的平方
你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
public class Case977 {public static void main(String[] args) {int[] nums = {-4,-1,0,3,10};//返回数组内容的字符串表示形式System.out.println(Arrays.toString(sortedSquares(nums)));}public static int[] sortedSquares(int[] nums) {int len = nums.length;for (int i = 0; i < nums.length; i++) {nums[i] = (int) Math.pow(nums[i],2);}Arrays.sort(nums);return nums;}
}
总结:利用api快速解题,时间复杂度为O(nlogn)。再学一招:双指针!O(n) 思路:数组有序,那么数组元素平方后,最大值只可能在两边,不可能在中间,如{-5,-4,-3,-2,-1,0,1},所以可以用双指针进行解答。
public static int[] sortedSquares2(int[] nums) {int n = nums.length;int[]res = new int[n];int i = 0;int j = n-1;int k = n-1;while (i<=j){if (nums[i]*nums[i] < nums[j]*nums[j]){res[k--] = nums[j]*nums[j];j--;}else {res[k--] = nums[i]*nums[i];i++;}}return res;
}
3.lc209【middle】 求长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target的长度最小的连续子数组 并返回其长度,如果不存在符合条件的子数组,返回 0 。
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
思路1:暴力,是最容易想到的方法,但超时了。时间复杂度为O(n*n)
public static int minSubArrayLen(int target, int[] nums) {int min = Integer.MAX_VALUE;for (int i = 0; i < nums.length; i++) {int sum = nums[i];if (sum >= target) return 1;for (int j = i + 1; j < nums.length; j++) {sum += nums[j];if (sum >= target) {min = Math.min(min, j - i + 1);break; //发现符合情况的,没必要往后加了,直接跳出本次循环。}}}return min==Integer.MAX_VALUE ? 0:min;
}
思路2:滑动窗口。时间复杂度为O(n),这种滑动窗口的类型是先找到符合条件的子数组,如果找不到往后拓展窗口的长度,直到找到为止(可能>>target),后改变起始位置,缩小滑动窗口。
public static int minSubArrayLen2(int target, int[] nums) {int left = 0;int sum = 0;int res = Integer.MAX_VALUE;//j 表示的是滑动窗口的终止位置。那么起始位置需要我们自己去调。for (int right = 0; right <nums.length ; right++) {sum += nums[right];while (sum>=target){res = Math.min(res,right-left+1);sum-=nums[left++];}}return res==Integer.MAX_VALUE?0:res;
}
4.删除有序数组中的重复项。
给你一个 非严格递增排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums
中唯一元素的个数。
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
public static int removeDuplicates(int[] nums) {int i = 0;for (int j = 1; j < nums.length; ) {if (nums[i]!=nums[j]){i++;nums[i] = nums[j];}else {j++;}}return i+1;
}
5.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n)
的算法。
输入: nums = [1,3,5,6], target = 5
输出: 2
public static 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){left = mid+1;}else if (nums[mid] >target){right = mid-1;}else {return mid;}
}
return left;
}
思路:看见题目要求时间复杂度为O(logn)必然要想到二分查找!但前提是数组有序,接下来就是在二分查找模板的基础上进行改动!
6.合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1
和 nums2
,另有两个整数 m
和 n
,分别表示 nums1
和 nums2
中的元素数目。请你 合并 nums2
到 nums1
中,使合并后的数组同样按 非递减顺序 排列。
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
思路一:利用api,快速解题,时间复杂度为O((n+m)log(m+n))
public static void merge(int[] nums1, int m, int[] nums2, int n) {
// for (int i = 0; i!=n ; i++) {
// nums1[m+i] = nums2[i];
// }System.arraycopy(nums2,0,nums1,m,n);Arrays.sort(nums1);
思路2:开辟一个一个辅助数组。时间复杂度O(n),空间复杂度O(n+m)。
public static void merge2(int[] nums1, int m, int[] nums2, int n) {int[]temp = new int[m];System.arraycopy(nums1,0,temp,0,m);//把nums1里面的元素,下标从0开始复制到temp里,下标从0开始,复制m个数。int p1 = 0; //指向tempint p2 = 0; //指向nums2int p = 0; //指向nums1的开头while ((p1<m)&&(p2<n)){nums1[p++] = temp[p1]<nums2[p2] ? temp[p1++] : nums2[p2++];}if (p1<m) System.arraycopy(temp,p1,nums1,p1+p2,m+n-p1-p2);// 如果p1走完的时候,p2还没走完,则把nums2从下标为p2的元素全部复制到nums1,复制m+n-p1-p2个元素if (p2<n) System.arraycopy(nums2,p2,nums1,p1+p2,m+n-p1-p2);
}
class Solution {public void merge(int[] A, int m, int[] B, int n) {for (int i = 0; i != n; ++i) {A[m + i] = B[i];}Arrays.sort(A);}
}
7.螺旋矩阵I [middle]
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
例如:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
思路:依次从左往右,从上到下,从右往左,从下往上依次遍历。
List<Integer> list = new ArrayList<>();
int left = 0;
int right = matrix[0].length-1; //列数
int up = 0;
int down = matrix.length-1; //行数
while (true){//左——>右for (int j = left; j <=right ; j++) {list.add(matrix[up][j]);}//第一行遍历完毕,开始遍历下面。if (++up>down){break;}//从上往下for (int i = up; i <= down; i++) {list.add(matrix[i][right]);}if (--right<left){break;}//从右往左for (int j = right; j>=left ; j--) {list.add(matrix[down][j]);}if (--down<up){break;}//从下往上for (int i = down; i >=up ; i--) {list.add(matrix[i][left]);}if (++left>right){break;}
}
return list;
}
8.螺旋矩阵||
你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
思路:与螺旋矩阵I 模板一模一样,无非定义一个变量num,初始值为1,在每个循环体里面自增。
9.返回数组中正整数数目与负整数数目中的最大值
给你一个按 非递减顺序 排列的数组 nums
,返回正整数数目和负整数数目中的最大值。换句话讲,如果 nums
中正整数的数目是 pos
,而负整数的数目是 neg
,返回 pos
和 neg
二者中的最大值。
nums = [-3,-2,-1,0,0,1,2]
输出:3
解释:共有 2 个正整数和 3 个负整数。计数得到的最大值是 3
public static int maximumCount(int[] nums) {int len = nums.length;int cntNeg = negNum(nums) + 1;int cntPos = len-posNum(nums);return Math.max(cntNeg, cntPos);
}private static int negNum(int[] nums) {//二分,求负数的个数。int i = 0;int j = nums.length - 1;while (i <= j) {int mid = (i + j) / 2;if (nums[mid] < 0) {i = mid + 1;} else {j = mid - 1;}}return j;
}
private static int posNum(int[] nums) {//二分,求负数和0的个数。int i = 0;int j = nums.length - 1;while (i <= j) {int mid = (i + j) / 2;if (nums[mid] >=1 ) {j = mid - 1;} else {i = mid+1;}}return i;
}