20230912刷题记录_双指针、数组

20230912刷题记录
参考【代码随想录】来刷的。
4 排序数组中的两数之和、5 三数之和来自《剑指Offer专项突破版》。
关键词:双指针、数组

1 有序数组的平方

977.有序数组的平方
力扣题目链接

1.1 暴力法

将该数组平方后排序,显然时间复杂度O(nlogn)。

1.2 双指针

该数组在平方之前是有序的,故平方后数组中的最大值在数组的两端,即要么在最左边,要么在最右边。
此时可以考虑双指针法了。
定义一个新数组result,和原数组一样的大小,让k指向result数组的最后一个元素。
i、j分别指向原数组的第一个元素和最后一个元素。
如果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];

时间复杂度为O(n),因为创建了一个长度为n的新数组,故空间也是O(n)。

class Solution {
    public int[] sortedSquares(int[] nums) {
        int i = 0;
        int j = nums.length - 1;
        int k = nums.length - 1;
        int[] result = new int[nums.length];

        while (i <= j) {
            if (nums[i]*nums[i] >= nums[j]*nums[j]) {
                result[k] = nums[i] * nums[i];
                ++i;
            } else {
                result[k] = nums[j] * nums[j];
                --j;
            }
            --k;
        }

        return result;
    }
}

2 长度最小的子数组

209.长度最小的子数组
力扣题目链接

双指针

使用两个指针i、j,i指向子数组的第一个元素,j指向子数组的最后一个元素,初始值都为0。
如果子数组的总和满足条件,使 i 向右移动。
如果子数组的总和不满足条件,使 j 向右移动。
i 每向右移动一步,相当于从子数组的最左边删除一个元素,子数组的长度也减1。由于数组中都是正整数,删除子数组中的元素,会使子数组的总和减少。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i = 0;
        int sum = 0;
        int minLength = Integer.MAX_VALUE;
        for (int j = 0; j < nums.length; j++) {
            sum += nums[j];
            while (sum >= target) {
                minLength = Math.min(minLength, j - i + 1);
                sum -= nums[i];
                i++;
            }
        }
        return minLength == Integer.MAX_VALUE ? 0 : minLength;
    }
}

3 螺旋矩阵II

力扣题目链接

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。
按照固定规则来遍历,左闭右开。
在这里插入图片描述

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        int count = 1;
        int loop = 0;
        while (loop <= n / 2) {
            for (int i = loop; i < n - 1 - loop; i++) {
                result[loop][i] = count++;
            }
            for (int i = loop; i < n - 1 - loop; i++) {
                result[i][n - 1 - loop] = count++;
            }
            for (int i = n - 1 - loop; i > loop ; i--) {
                result[n- 1 - loop][i] = count++;
            }
            for (int i = n - 1 - loop; i > loop ; i--) {
                result[i][loop] = count++;
            }
            loop++;
        }

		// 对奇数阶矩阵的中心的处理
        if (n % 2 == 1) {
            result[n / 2][n / 2] = count;
        }

        return result;
    }
}

4 排序数组中的两数之和

给定一个递增排序的整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [2,3,4], target = 6
输出:[1,2]

4.1 哈希表

扫描数组,假设扫描到数字i,如果哈希表中存在另一个数字target - i,那么就找到了;如果不存在则将i存入哈希表。
显然该算法的时间复杂度是O(n),空间复杂度是O(n)。

4.2 双指针

使用两个指针i、 j,分别指向数组的第一个元素和最后一个元素。
如果nums[i] + nums[j] > target,i向右移动一位,
如果nums[i] + nums[j] < target,j向左移动一位。
显然该算法的时间复杂度时O(n),空间复杂度是O(1)。

public class Order6 {
    public int[] twoSum(int[] numbers, int target) {
        int i = 0;
        int j = numbers.length - 1;
        while (i < j && numbers[i] + numbers[j] != target) {
            if (numbers[i] + numbers[j] > target) {
                j--;
            } else {
                i++;
            }
        }
        return new int[]{i, j};
    }
}

5 三数之和

力扣题目链接
如果数组是有序的,可固定一个数 i,然后找出两数之和为 -i 的两个数即可。
显然时间复杂度是O(n^2)。
如果该数组无序,则需要先把数组排序,时间复杂度为O(nlogn)+O(n^2),
仍然是O(n^2)。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        if (nums.length < 3)
            return null;
        List<List<Integer>> result = new ArrayList<>();
        int i = 0;
        Arrays.sort(nums);
        while (i < nums.length - 2) {
            twoSum(nums, i, result);
            int temp = nums[i];
            while (temp == nums[i] && i < nums.length - 2)
                ++i;
        }
        return result;
    }

    private void twoSum(int[] nums, int i, List<List<Integer>> result) {
        int j = i + 1;
        int k = nums.length - 1;
        while (j < k) {
            if (nums[i] + nums[j] + nums[k] == 0) {
                result.add(Arrays.asList(nums[i], nums[j], nums[k]));
                
                int temp = nums[j];
                while (temp == nums[j] && j < k) 
                    ++j;
            } else if (nums[i] + nums[j] + nums[k] > 0)     
                --k;
            else 
                ++j;
            
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值