977. 有序数组的平方
暴力排序
最直观的想法,莫过于:每个数平方之后,排个序,美滋滋,代码如下:
Java:
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;
}
}
Golang:
func sortedSquares(nums []int) []int {
ans := make([]int, len(nums))
for i, v := range nums{
ans[i] = v * v
}
sort.Ints(ans)
return ans
}
双指针法
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
如果A[i] * A[i] < A[j] * A[j]
那么result[k--] = A[j] * A[j];
。
如果A[i] * A[i] >= A[j] * A[j]
那么result[k--] = A[i] * A[i];
。
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length - 1;
int[] res = new int[nums.length];
int j = nums.length - 1;
while(l <= r){
if(nums[l] * nums[l] > nums[r] * nums[r]){
res[j--] = nums[l] * nums[l++];
}else{
res[j--] = nums[r] * nums[r--];
}
}
return res;
}
}
209. 长度最小的子数组
暴力解法
两个for循环,然后不断的寻找符合条件的子序列,时间复杂度是O(n^2)。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int result = Integer.MAX_VALUE;
int length = 0;
int sum = 0;
int k = 1;
for(int i = 0;i < nums.length;i ++){
sum = 0;
for(int j = i;j < nums.length;j ++){
sum += nums[j];
if(sum >= target){
length = j - i + 1;
result = result < length ? result : length;
break;
}
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
//代码最终超时了。。
滑动窗口
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
解题的关键在于 窗口的起始位置如何移动,如图所示:
可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
Java:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
//滑动窗口
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for(int right = 0;right < nums.length;right ++){
sum += nums[right];
while(sum >= target){
result = Math.min(result,right - left + 1);
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
Golang:
func minSubArrayLen(target int, nums []int) int {
if len(nums) == 0{
return 0
}
start, end := 0, 0
sum := 0
ans := math.MaxInt32
for end < len(nums){
sum += nums[end]
for sum >= target{
sum -= nums[start]
ans = min(ans, end - start + 1)
start ++
}
end ++
}
if ans == math.MaxInt32{
return 0
}
return ans
}
func min(x, y int) int{
if x < y{
return x
}
return y
}
59. 螺旋矩阵 II
不涉及算法,模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
Java:
class Solution {
public int[][] generateMatrix(int n) {
int loop = 0;
int[][] res = new int[n][n];
int start = 0;
int count = 1;
int i,j;
while(loop++ < n/2){
//上侧从左到右 左闭右开
for(j = start;j < n - loop;j ++){
res[start][j] = count ++;
}
//右侧从上到下 上闭下开
for(i = start;i < n - loop;i ++){
res[i][j] = count ++;
}
//下侧从右到左 右闭左开
for(;j >= loop;j --){
res[i][j] = count ++;
}
//左侧从下到上 下闭上开
for(;i >= loop;i --){
res[i][j] = count ++;
}
start ++;
}
if(n % 2 == 1){
res[start][start] = count;
}
return res;
}
}
Golang:
type pair struct{ x, y int }
var dirs = []pair{{0, 1}, {1, 0}, {0, -1}, {-1, 0}} // 右下左上
func generateMatrix(n int) [][]int {
matrix := make([][]int , n)
for i := range matrix{
matrix[i] = make([]int, n)
}
row, col, dirIdx := 0, 0, 0
for i := 1; i <= n*n; i++ {
matrix[row][col] = i
dir := dirs[dirIdx]
if r, c := row+dir.x, col+dir.y; r < 0 || r >= n || c < 0 || c >= n || matrix[r][c] > 0 {
dirIdx = (dirIdx + 1) % 4 // 顺时针旋转至下一个方向
dir = dirs[dirIdx]
}
row += dir.x
col += dir.y
}
return matrix
}