力扣记录:剑指offer(3)——JZ24-32

JZ24 反转链表

  • 双指针,左指针指向上一个元素,右指针指向当前元素,右指针元素指向左指针元素
    • 时间复杂度O(n),空间复杂度O(1)
class Solution {
    public ListNode reverseList(ListNode head) {
        //双指针
        ListNode left = null;
        ListNode right = head;
        //临时变量交换
        ListNode temp = null;
        while(right != null){
            temp = right.next;
            right.next = left;
            left = right;
            right = temp;
        }
        //返回结果
        return left;
    }
}
  • 递归,同双指针
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    public ListNode reverseList(ListNode head) {
        //递归
        return reverse(null, head);
    }
    private ListNode reverse(ListNode left, ListNode right){
        //右指针到尾时结束
        if(right == null) return left;
        //临时变量交换
        ListNode temp = right.next;
        right.next = left;
        left = right;
        right = temp;
        //递归
        return reverse(left, right);
    }
}

JZ25 合并两个排序的链表

  • 迭代,定义虚拟头结点依次取两条链表的较小节点
    • 时间复杂度O(m+n),空间复杂度O(1)
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        //定义虚拟头结点
        ListNode virtualHead = new ListNode(0);
        //定义处理的当前节点
        ListNode cur = virtualHead;
        //将节点指向两个链表中较小的那个节点
        while(l1 != null && l2 != null){
            if(l1.val > l2.val){
                cur.next = l2;
                l2 = l2.next;
            }else{
                cur.next = l1;
                l1 = l1.next;
            }
            //移动当前节点
            cur = cur.next;
        }
        //将剩下非空的链表直接放在后面
        cur.next = (l1 == null ? l2 : l1);
        //返回结果
        return virtualHead.next;
    }
}
  • 递归,返回当前节点中较小的,当前节点指向两条链路下一节点节点中较小的节点
    • 时间复杂度O(m+n),空间复杂度O(m+n)
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        //递归
        if(l1 == null){
            return l2;
        }else if(l2 == null){
            return l1;
        }else if(l1.val > l2.val){
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }else{
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }
    }
}

JZ26 树的子结构

  • 递归,B为A的子结构或B为A左子树的子结构或B为A右子树的子结构。
    • 时间复杂度O(mn),空间复杂度O(m)
class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        //A或B为空则为false
        if(A == null || B == null) return false;
        //递归
        boolean res1 = compareStructure(A, B);//B为A的子结构
        boolean res2 = isSubStructure(A.left, B);//B为A左子树的子结构
        boolean res3 = isSubStructure(A.right, B);//B为A右子树的子结构
        return res1 || res2 || res3;
    }
    //判断B是否在A的子结构
    private boolean compareStructure(TreeNode A, TreeNode B){
        //遍历完B后直接返回true
        if(B == null) return true;
        if(A == null && B != null) return false;
        //当前节点相同,递归
        if(A.val == B.val){
            return compareStructure(A.left, B.left) && compareStructure(A.right, B.right);
        }
        return false;
    }
}

JZ27 二叉树的镜像

  • 递归,可以在本函数直接递归,注意左右子树赋值
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        //判断特殊情况
        if(root == null) return null;
        //递归
        //前序遍历
        TreeNode temp = root.left;
        //交换左右子树
        root.left = mirrorTree(root.right);
        root.right = mirrorTree(temp);
        return root;
    }
}

JZ28 对称的二叉树

  • 递归,注意判断同一侧:内侧和外侧
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    public boolean isSymmetric(TreeNode root) {
        //判断特殊情况
        if(root == null) return true;
        //递归
        return compareSymmetric(root.left, root.right);
    }
    //判断两棵子树对应位置是否一致
    private boolean compareSymmetric(TreeNode left, TreeNode right){
        if(left == null && right != null) return false;
        if(left != null && right == null) return false;
        if(left == null && right == null) return true;
        //若当前节点一致,继续判断内侧和外侧
        if(left.val == right.val) return compareSymmetric(left.left, right.right) && compareSymmetric(left.right, right.left);
        return false;
    }
}

JZ29 顺时针打印矩阵

  • 模拟打印顺序,注意循环次数(圈数)、每次循环四条边的起点和终点、最后中心部分的处理。
    • 时间复杂度O(mn),空间复杂度O(1)
class Solution {
    public int[] spiralOrder(int[][] matrix) {
        //模拟打印顺序
        int m = matrix.length;  //行数
        if(m == 0){ //判断特殊情况
            int[] res = {};
            return res;
        }
        int n = matrix[0].length;   //列数
        int[] res = new int[m * n]; //结果及下标计数
        int count = 0;
        int loop = Math.min(m, n) / 2;  //循环次数,圈数
        //第一圈圈第一条边的起点
        int startX = 0;
        int startY = 0;
        //第一圈横竖边长度
        int lengX = n - 1;
        int lengY = m - 1;
        //开始模拟
        while(loop >= 1){
            //每圈第一条边的起点
            int i = startX;
            int j = startY;
            //第一条边
            for(; j < lengX; j++){
                res[count++] = matrix[i][j];
            }
            //第二条边
            for(; i < lengY; i++){
                res[count++] = matrix[i][j];
            }
            //第三条边
            for(; j > startX; j--){
                res[count++] = matrix[i][j];
            }
            //第四条边
            for(; i > startY; i--){
                res[count++] = matrix[i][j];
            }
            //修改下一次循环的起点和边长度
            startX++;
            startY++;
            lengX--;
            lengY--;
            loop--;
        }
        //最后处理中心部分
        if(m > n){
            //行数m大于列数n时,且n为奇数时,中心为(m-循环次数*2)*1的矩阵
            //起点即为循环次数,终点为起点加长度,纵向
            if(n % 2 == 1){
                loop = n / 2;   //循环次数
                int leng = m - loop;    //终点
                //开始添加
                for(int i = loop; i < leng; i++){
                    res[count++] = matrix[i][loop];
                }
            }
        }else if(m < n){
            //行数m小于列数n时,且m长度为奇数时,中心为1*(n-循环次数*2)的矩阵
            //起点即为循环次数,终点为起点加长度,横向
            if(m % 2 == 1){
                loop = m / 2;   //循环次数
                int leng = n - loop;    //终点
                //开始添加
                for(int j = loop; j < leng; j++){
                    res[count++] = matrix[loop][j];
                }
            }
        }else{
            //行数m等于列数n时,且长度为奇数时,中心为1*1矩阵
            if(m % 2 == 1){
                loop = m / 2;   //中心点即为循环次数
                //开始添加
                res[count++] = matrix[loop][loop];
            }
        }
        return res;
    }
}

JZ30 包含min函数的栈

  • 定义辅助栈保存当前栈中的最小值。
    • 时间复杂度O(1),空间复杂度O(n)
class MinStack {
    //定义辅助栈和输出栈
    Deque<Integer> stackm;
    Deque<Integer> stackOut;
    /** initialize your data structure here. */
    public MinStack() {
        //初始化(可以初始化辅助栈入栈int最大值)
        stackm = new LinkedList<>();
        stackOut = new LinkedList<>();
    }
    //入栈时进行判断,保证辅助栈栈顶保存当前最小元素
    public void push(int x) {
        //输出栈直接入栈
        stackOut.push(x);
        //辅助栈为空时直接入栈
        if(stackm.isEmpty()){
            stackm.push(x);
        }else{
            //若当前元素小于辅助栈最小值,则压入当前元素,否则再压入辅助栈最小值
            stackm.push(Math.min(stackm.peek(), x));
        }
    }
    //出栈时直接出栈
    public void pop() {
        stackOut.pop();
        stackm.pop();
    }
    //判断输出栈栈顶
    public int top() {
        return stackOut.peek();
    }
    //判断辅助栈栈顶
    public int min() {
        return stackm.peek();
    }
}

JZ31 栈的压入、弹出序列

  • 模拟栈的压入弹出,遍历弹入数组和弹出数组,对于栈有三种可能,将将弹入数组当前元素压入再弹出、将栈顶元素弹出、将弹入数组当前元素压入栈。
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        //模拟
        int leng1 = pushed.length;
        int leng2 = popped.length;
        Deque<Integer> stackPush = new LinkedList<>();
        //判断特殊情况
        if(leng1 == 0 && leng2 == 0) return true;
        int i = 0;
        int j = 0;
        while(j < leng2 && i <= leng1){
            if(!stackPush.isEmpty() && stackPush.peek() == popped[j]){
                stackPush.pop();
                j++;
            }else if(i < leng1 && pushed[i] == popped[j]){
                i++;
                j++;
            }else{
                if(i >= leng1) break;
                stackPush.push(pushed[i++]);
            }
        }
        return j == leng2;
    }
    //优化
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Deque<Integer> stackPush = new LinkedList<>();
        int j = 0;
        for(int p : pushed){
            stackPush.push(p);
            while(!stackPush.isEmpty() && stackPush.peek() == popped[j]){
                stackPush.pop();
                j++;
            }
        }
        return stackPush.isEmpty();
    }
}

JZ32-I 从上到下打印二叉树

  • 层序遍历。
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    public int[] levelOrder(TreeNode root) {
        //判断特殊情况
        if(root == null){
            int[] result = {};
            return result;
        }
        //层序遍历,使用队列
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<Integer> res = new ArrayList<>();
        //初始化
        queue.offer(root);
        //开始遍历
        while(!queue.isEmpty()){
            int leng = queue.size();    //每层的长度
            for(int i = 0; i < leng; i++){
                TreeNode cur = queue.poll();
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
                res.add(cur.val);
            }
        }
        //将可变数组转为数组
        int[] result = new int[res.size()];
        result = res.stream().mapToInt(Integer::valueOf).toArray();
        //也可遍历赋值
        // for(int i = 0; i < res.size(); i++)
        //     result[i] = res.get(i);
        return result;
    }
}

JZ32-II 从上到下打印二叉树II

  • 层序遍历,每一层保存为一个数组。
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //层序遍历,使用队列
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<List<Integer>> res = new ArrayList<>();
        //判断特殊情况
        if(root == null) return res;
        queue.offer(root);  //初始化
        while(!queue.isEmpty()){
            int leng = queue.size();    //每层长度
            ArrayList<Integer> resLine = new ArrayList<>();
            for(int i = 0; i < leng; i++){
                TreeNode cur = queue.poll();
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
                resLine.add(cur.val);    //保存该层元素
            }
            res.add(resLine);   //保存每层结果
        }
        //将可变数组转为数组
        return res;
    }
}

JZ32-III 从上到下打印二叉树III

  • 层序遍历,使用双端队列(存过程或结果),每一层保存为一个数组,同时定义变量决定当前层为正序或反序。
    • 时间复杂度O(n),空间复杂度O(n)
class Solution {
    //过程
    public List<List<Integer>> levelOrder(TreeNode root) {
        //层序遍历,使用双端队列
        Deque<TreeNode> deque = new LinkedList<>();
        ArrayList<List<Integer>> res = new ArrayList<>();
        //判断特殊情况
        if(root == null) return res;
        deque.offer(root);  //初始化
        boolean flag = true;   //决定当前层遍历顺序,true为正序,false为反序
        while(!deque.isEmpty()){
            int leng = deque.size();    //当前层长度
            ArrayList<Integer> resLine = new ArrayList<>();
            TreeNode cur = new TreeNode(-1);
            for(int i = 0; i < leng; i++){
                if(flag){   //正序
                    cur = deque.pollFirst();
                    if(cur.left != null) deque.offerLast(cur.left);
                    if(cur.right != null) deque.offerLast(cur.right);
                }else{
                    cur = deque.pollLast();
                    if(cur.right != null) deque.offerFirst(cur.right);
                    if(cur.left != null) deque.offerFirst(cur.left);
                }
                resLine.add(cur.val);       
            }
            res.add(resLine);
            flag = !flag;
        }
        return res;
    }
    //结果
    public List<List<Integer>> levelOrder(TreeNode root) {
        //层序遍历,使用队列
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<List<Integer>> res = new ArrayList<>();
        //判断特殊情况
        if(root == null) return res;
        queue.offer(root);  //初始化
        boolean flag = true;   //决定当前层遍历顺序,true为正序,false为反序
        while(!queue.isEmpty()){
            int leng = queue.size();    //每层长度
            Deque<Integer> resLine = new LinkedList<>(); //使用双端队列
            for(int i = 0; i < leng; i++){
                TreeNode cur = queue.poll();
                if(flag){   //正序
                    resLine.offerLast(cur.val);
                }else{  //反序
                    resLine.offerFirst(cur.val);
                }
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
            }
            res.add(new LinkedList<Integer>(resLine));   //保存每层结果
            flag = !flag;
        }
        //将可变数组转为数组
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值