leetCode刷题日记01【513, 209, 24】

目录

513.找树左下角的值

题目描述

解题思路

代码

209.长度最小的子数组

题目描述

解题思路

代码

24. 两两交换链表中的节点

题目描述

解题思路

代码


513.找树左下角的值

题目描述

513.找树左下角的值

解题思路

找深度最大的叶子节点

再用前中后序遍历(只要保证逻辑左在右的前面就可以,中只是个形式因为最左下角的值要么是左侧要么是右侧,后续是左右中)

代码

全局变量:

目前最大深度(maxDepth)

结果:记录当前节点的数值(result)(如果比目前最大深度大则更新result)

1. 方法传参:遍历(当前节点,深度)

2. 终止条件:当前节点为空则return

3. 单层递归的逻辑:

遍历到叶子节点(左孩子和右孩子都等于空)

【如果当前深度大于目前最大深度则更新maxDepth和result(这样才能使遍历完之后result存的是深度最大的叶子结点的值)】

【左在右前面】如果左节点不为空(否则操作空指针)则深度加加,再向左遍历(递归),递归完需要回溯到上层(也就是深度减减)然后再深度加加,再向右遍历(递归),递归完依然需要回溯到上层(也就是深度减减)

不需要写中的逻辑也是在于只要保证逻辑左在右的前面就可以,中只是个形式

depth++;
traversal(root-> left, depth);
depth--;

可以简化成traversal(root-> left, depth+1);

class Solution {
    // 全局变量:最大深度和目标值
    int maxDepth = -1;
    int result = 0;

    public int findBottomLeftValue(TreeNode root) {
        findMaxDepthLeftNode(root, 0);
        return result;
    }

    private void findMaxDepthLeftNode(TreeNode cur, int depth) {
        // 终止条件:如果当前节点为空值则return
        if (cur == null) return;

        // 单层递归逻辑:判断是否是叶子节点(左右子节点都为空),如果是叶子结点,当前深度大于最大深度则更新,以及更新节点所对应的值
        if (cur.left == null && cur.right == null) {
            if (depth > maxDepth) {
                maxDepth = depth;
                result = cur.val;
            }
        }

        // 单层递归逻辑:进行遍历(只要左子树遍历在右之前就可以,因为不需要中序遍历,只要找子节点)
        // 排除空指针问题
        // findMaxDepthLeftNode(cur.left, depth + 1) 由于递归回溯【每次递归调用中将当前深度加一,但不改变原有 depth 的值】其实等于 
        // depth ++
        // findMaxDepthLeftNode(cur.left, depth)
        // depth --
        if (cur.left != null) findMaxDepthLeftNode(cur.left, depth + 1);
        // 不能else if,因为遍历左子树和右子树独立,否则逻辑变成只有左子树不存在才会遍历右子树
        if (cur.right != null) findMaxDepthLeftNode(cur.right, depth + 1);
    }
}

209.长度最小的子数组

题目描述

209.长度最小的子数组

解题思路

滑动窗口:一个for循环做两个for循环的任务(循环的索引,一定是表示滑动窗口的终止位置

什么时候移动起始位置:当发现当前滑动窗口长度>=s则移动起始位置

引用代码随想录该题的思路动图,很清晰

209.长度最小的子数组

 滑动窗口主要考虑三点:

1. 窗口内是什么:满足和大于等于s的最小长度的连续子数组

2. 终止位置:窗口结束位置也就是遍历数组的指针(for循环)

3. 起始位置:如果当前的和s大于s则需要移动了(删除“左边”的元素以缩小窗口)

代码

全局变量:

start(窗口起始指针)、sum(记录求和)、result(记录当前最优子数组长度)【定义为最大值用来向下更新】

for循环由于是控制终止位置指针(finish=0, finish <= nums.length, finish++)

【每次循环求和sum += nums[finish],当求和【这里应该是while而不是if因为需要达到一个窗口持续移动的过程,否则会导致有可能缩减了1个长度并没有达到最优解】sum >= target则需要知晓对应的长度(也就是subLength = finish-start+1)以及更新最优子数组长度(result = min(result, subLength))。此时因为sum>=target说明需要缩小窗口因此sum -= nums[start](也就是删掉起始位置【右边】的元素),再把起始位置指针移动(start++)】

因为有可能无解所以需要return 

return result == Integer.MAX_VALUE ? 0 : result;
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        // 全局变量:
        // 窗口起始指针
        int start = 0;
        // 记录当前求和
        int sum = 0;
        // 记录最小长度(因为有可能不存在所以需要赋值一个无限大值)
        int result = Integer.MAX_VALUE;
        // 遍历窗口终止指针
        for (int finish = 0; finish < nums.length; finish++) {
            // 当前求和
            sum += nums[finish];
            while (sum >= target) {
                // 满足窗口内条件则计算窗口长度
                int subLength = finish - start + 1;
                result = Math.min(subLength, result);
                // 移动窗口起始指针以缩小窗口
                sum -= nums[start];
                start++;
            }
        }
        // 因为有可能不存在答案因此要判断
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

24. 两两交换链表中的节点

题目描述

24. 两两交换链表中的节点

解题思路

交换的是指针而不是节点里的值

用dummyHead做头结点

指针需要指向需要反转的两个节点的前一个节点的上一个节点(方便改变指向)

例如1->2->3那么加在1的前面dummyHead->1->2->3然后变成dummyHead->2->1->3

交换链表什么时候终止?什么时候该交换节点?

引用代码随想录该题的思路图,很清晰

代码

加入dummyHead做头结点(dummyHead.next = head)

让当前节点也用dummyHead赋值(cur = dummyHead)

终止条件:

如果节点数是偶数,则当前节点的下一个为空;为奇数,则当前节点的下一个的下一个为空;(while (cur.next != null && cur.next.next != null))【因为这两个情况“或”满足则终止,因此反过来while后面跟的是循环成立的情况,补集则是&&然后两个==变成!=】

交换节点的逻辑:

第一步,首先需要把dummyHead指向节点2(cur.next = cur.next.next)

第二步,需要把节点2指向节点1。如果没有第一步则节点1对应cur.next,但因为第一步所以导致cur.next变节点2了,因此需要在第一步之前用一个临时节点接住节点1对应的指针(temp1 = cur.next)否则这回操作节点1并不是cur.next了

第三步,需要把节点1指向节点3。(temp1.next = temp2)同理因为第二步节点2指向节点1了。因此节点3的被指向断了,因此需要在第一步之前用temp2保存节点3的指针(temp2 = cur.next.next.next)

然后把cur往后移动两位(因为交换两个因此需要移动到需要交换的后一个节点的位置)(cur = cur.next.next)

最后return 头结点(dummyhead.next)

class Solution {
    public ListNode swapPairs(ListNode head) {
        // 新建一个虚拟头结点
        ListNode dummyHead = new ListNode(-1);

        // 把虚拟头结点的下一个设置为头结点
        dummyHead.next = head;

        // 把当前指针设置为虚拟头结点,这样才能方便操控后面的节点的交换
        ListNode cur = dummyHead;

        // 设置终止条件:节点奇数个时,下下个节点为空;偶数个时,下个节点为空
        // 补集因为while后是循环成立条件因此||变成&&以及==变成!=
        while (cur.next != null && cur.next.next != null) {
            // 交换节点的逻辑
            // 用临时节点把节点1、2、3保存。否则在后续next指针改变的时候会丢失原先的指针
            // [这个暂存指针的三行代码必须在检查了cur.next以及cur.next.next都不是空值之后才能写,也就是不能写在循环外面,否则还是会报空指针错误]
            ListNode temp1 = cur.next;
            ListNode temp2 = cur.next.next;
            ListNode temp3 = cur.next.next.next;
            // 第一步:dummyHead指向节点2
            cur.next = temp2;

            // 第二步:节点2指向节点1
            temp2.next = temp1;

            // 第三步:节点1指向节点3
            temp1.next = temp3;

            // 移动cur指针进而帮助下一对节点交换(因为帮助了两个节点交换,也就是移动到需要交换的后一个节点)
            cur = cur.next.next;
        }
        // 返回头结点(dummyHead.next而不是dummyHead)
        return dummyHead.next;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值