开始学算法2===>双指针算法+螺旋矩阵(LeetCode刷题!!!)

跟着carl哥的第二天

今天仔细学了双指针算法,以及推演了螺旋矩阵。通过这篇文章可以让你更快认识到双指针算法的魅力,以及螺旋矩阵的基本做法。

双指针算法

先看第一道题

leetcode977.有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例1:

输入:nums = [-4,-1,0,3,10] 
输出:[0,1,9,16,100] 
解释:平方后,数组变为 [16,1,0,9,100],
		排序后,数组变为 [0,1,9,16,100]

示例2:

输入:nums = [-7,-3,2,3,11] 
输出:[4,9,9,49,121]

这道题先设想一下,如果双指针的话该怎么做,怎么样找出数组中的最大值,然后放在新数组的最后位,只要解决第一步后面就都迎刃而解了!


答案:::

public class test01 {

    //定义输入输出
    public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

    public static void main(String[] args) throws IOException {

        //读入一行,并按照空格拆分
        String s = in.readLine();
        String[] str = s.split(",");
        int n = str.length;


        //转为int数组
        int[] nums = new int[n];
        for (int i = 0; i < n; i ++) {
            nums[i] = Integer.parseInt(str[i]);
        }

        int[] arr = sortedSquares(nums);
        out.write(Arrays.toString(arr));
        out.flush();
        out.close();
        //System.out.println(Arrays.toString(arr));

    }

    private static int[] sortedSquares(int[] nums) {

        int left = 0;
        int right = nums.length - 1;
        int[] result = new int[nums.length];
        int index = nums.length - 1;
        while(index != -1) {

            //左边的平方大于右边的平方
            if (nums[left] * nums[left] >= nums[right] * nums[right]) {

                result[index --] = nums[left] * nums[left];
                left ++;

            //右边的平方小于左边的平方
            } else {

                result[index --] = nums[right] * nums[right];
                right --;
            }
        }

        return result;
    }
}

通过指针指定左右两个边界,然后判断两边界的平方谁大即可解。

再看第二道题

209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例 :

输入:s = 7, nums = [2,3,1,2,4,3] 
输出:2 
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

用双指针算法来说就是:
你要怎么去找到任何一个子数组,子数组的范围跟里面的和该怎么定义。
找到任何一个子数组的话:我们需要去确定左边界跟右边界(又是两指针)
也就是说左边界跟右边界又该怎么去移动呢?
我们是通过子数组里边的和跟target去判断来移动左右两指针的。
左边界的移动:如果当前子数组里边的和大于target了,窗口就要向前移动了(也就是该缩小了)
右边界的移动:窗口的结束位置是遍历数组的指针,也就是for循环里的索引


答案:

public class test02 {

    //定义输入输出
    public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

    public static void main(String[] args) throws IOException {

        //读入一个数字,默认读入String 需要转为int
        Integer target = Integer.parseInt(in.readLine());

        //读入一行,并按照空格拆分
        String s = in.readLine();
        String[] str = s.split(" ");
        int n = str.length;

        //转为int数组
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = Integer.parseInt(str[i]);
        }

        int count = minSubArrayLen(nums, target);
        out.write(Integer.toString(count));
        out.flush();
        out.close();
    }

    private static int minSubArrayLen(int[] nums, Integer target) {

        int index = 0; //左边界
        int sum = 0; //子数组的和
        int result = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i ++) { //i为右边界

            sum += nums[i];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            //例子[1,1,1,1,100] target=100
            while (sum >= target) {

                //不断遍历,直到找出最小值
                result = Math.min(result, i - index + 1);
                //当子数组的值大于target时,我们需要让左指针往前走,来检查还能否符合条件
                sum -= nums[index ++];
            }
        }
        
        //如果没有找到合适的子数组,返回0
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

最后高频面试题:螺旋矩阵

leetcode59.螺旋矩阵II

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例:

  • 输入: 3
  • 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

思路:
一开始我也脑子是蒙的,然后我就自己推演了一下,用实例去推演了一圈,因为这种题应该是有规律的。

		假如 n=4 且我们只看最外圈
        //   0  1  2  3
        //0 [ 1, 2, 3, 4]
        //1 [12,13,14, 5]
        //2 [11,16,15, 6]
        //3 [10, 9, 8, 7]

        //设一个值,来给矩阵赋值
        int count = 1;

        //设置一个二位矩阵来存储螺旋矩阵
        int[][] res = new int[4][4];

        //设置起点的坐标
        int i = 0;
        int j = 0;

        //因为我们要循环四条边,所以我们需要找一个规律
        //使得四条边的规则是一样的
        //这里我们设置的是 4个for: 相同之处在于包含起点但不包含终点(终点是下条边的起点)
        //第一条边:1->3
        for (j = 0; j < n - 1; j ++)
            res[0][j] = count ++;
        //第二条边:4->6
        for (i = 0; i < n - 1; i ++)
            res[i][j] = count ++;
        //第三条边:7->9
        for (; j > 0; j --)
            res[i][j] = count ++;
        //第四条边:10->12
        for (; i > 0; i --)
            res[i][j] = count ++;

        //如果是n=奇数,那最中间的那个位置就没有值,所以我们设置一个mid
        //让累加到最后的count赋值给最终的位置
        int mid = n / 2;
        res[mid][mid] = count;*/

然后就很简单了,把里面的固定值换成符合题目的变量,让变量去代替固定值,这样就能把整个矩阵画出来了


答案:

public class test03 {

    public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
    public static void main(String[] args) throws IOException {

        int n = Integer.parseInt(in.readLine());
        int[][] result = new int[n][n];

        result = generateMatrix(n);
        out.write(Arrays.toString(result));
    }

    private static int[][] generateMatrix(int n) {
 
        int[][] result = new int[n][n];
        int count = 1;
        int startx = 0;   //起点的横坐标
        int starty = 0;   //起点的纵坐标

        //因为n=4 就只有两圈,所以就是n/2
        int loop = n / 2; //圈数
        int mid = n / 2;
        int offset = 1; //随之圈子的缩小,offset增加,也就是遍历每条边的长度
        while(loop -- > 0) {

            //记住这里定义的是下面4个for的全局变量
            int i = startx;
            int j = starty;

            for (j = starty; j < n - offset; j ++) {
                result[startx][j] = count ++;
            }
            for (i = startx; i < n - offset; i ++) {
                result[i][j] = count ++;
            }
            for (; j > starty; j --) {
                result[i][j] = count ++;
            }
            for (; i > startx; i --) {
                result[i][j] = count ++;
            }

            startx ++; //随之圈数增加 起始坐标也会越来越往中间
            starty ++;

            offset ++;
        }

        if (n % 2 == 1) {
            result[mid][mid] = count;
        }
        return result;
    }
}

自我总结

基本有了双指针算法的思想了~~ 大概吧应该吧。
然后学会高频面试题还是挺开心的嘿嘿

大概就是这样,大家懂了吗 有什么不懂的评论区评论或者私信我吧!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值