算法(2)

news2024/12/28 20:25:04

二叉树

镜像二叉树

树轴对称

image-20220714124446238

第一个节点的左子树与第二个节点的右子树同步递归对比,第一个节点的右子树与第二个节点的左子树同步递归比较。

二叉树序列化、反序列化

image-20220714132710644

当然你也可以根据满二叉树结点位置的标号规律来序列化,还可以根据先序遍历和中序遍历的结果来序列化。不对序列化之后的字符串进行约束,所以欢迎各种奇思妙想。

思路 : 序列化树,递归前序遍历,反序列化同。序列化为字符串 1!#22! ,用!分割灭一个数值,#区分空节点。

import java.util.*;
public class Solution {
    //序列的下标
    public int index = 0;
    //处理序列化的功能函数(递归)
    private void SerializeFunction(TreeNode root, StringBuilder str) {
        //如果节点为空,表示左子节点或右子节点为空,用#表示
        if (root == null) {
            str.append('#');
            return;
        }
        //根节点
        str.append(root.val).append('!');
        //左子树
        SerializeFunction(root.left, str);
        //右子树
        SerializeFunction(root.right, str);
    }

    public String Serialize(TreeNode root) {
        //处理空树
        if (root == null)
            return "#";
        StringBuilder res = new StringBuilder();
        SerializeFunction(root, res);
        //把str转换成char
        return res.toString();
    }
    //处理反序列化的功能函数(递归)
    private TreeNode DeserializeFunction(String str) {
        //到达叶节点时,构建完毕,返回继续构建父节点
        //空节点
        if (str.charAt(index) == '#') {
            index++;
            return null;
        }
        //数字转换
        int val = 0;
        //遇到分隔符或者结尾
        while (str.charAt(index) != '!' && index != str.length()) {
            val = val * 10 + ((str.charAt(index)) - '0');
            index++;
        }
        TreeNode root = new TreeNode(val);
        //序列到底了,构建完成
        if (index == str.length())
            return root;
        else
            index++;
        //反序列化与序列化一致,都是前序
        root.left = DeserializeFunction(str);
        root.right = DeserializeFunction(str);
        return root;
    }

    public TreeNode Deserialize(String str) {
        //空序列对应空树
        if (str == "#")
            return null;
        TreeNode res = DeserializeFunction(str);
        return res;
    }
}

二叉搜索树第k节点

中序遍历返回遍历的第k个节点。

返回二叉搜索树 两个节点的最近公共祖先

思路1:返回当前节点到p和q的距离之和,能获得最小的距离就是根节点。递归,可以适用于(非有序的),题目中给定有序,那就只要判断当前节点是不是 root.val >=p&&q>=root.val 或者root.val <= p&& q>= root.val的那个节点即可。

import java.util.*;
public class Solution {

    public int lowestCommonAncestor (TreeNode root, int p, int q) {
        if (root == null) return -1;
        if (root.val >= p && root.val <= q) {
            return root.val;
        } else if (root.val <= p && root.val >= q) {
            return root.val;
        } else {
            if (root.val < p) {
                return lowestCommonAncestor(root.right, p, q);
            } else {
                return lowestCommonAncestor(root.left, p, q);
            }
        }
    }
}

思路2:题目给定二叉搜索树,有序的,那就可以分别判断两个节点p、q在当前节点的左子树还是右子树。然后再遍历的过程中记录到达p或者q遍历过的元素路径,最后比较两个路径,最后一个相同的元素即是要求节点。

import java.util.*;
public class Solution {
    //求得根节点到目标节点的路径
    public ArrayList<Integer> getPath(TreeNode root, int target) {
        ArrayList<Integer> path = new ArrayList<Integer>();
        TreeNode node = root;
        //节点值都不同,可以直接用值比较
        while(node.val != target){ 
            path.add(node.val);
            //小的在左子树
            if(target < node.val) 
                node = node.left;
            //大的在右子树
            else 
                node = node.right;
        }
        path.add(node.val);
        return path;
    }
    public int lowestCommonAncestor (TreeNode root, int p, int q) {
        //求根节点到两个节点的路径
        ArrayList<Integer> path_p = getPath(root, p); 
        ArrayList<Integer> path_q = getPath(root, q);
        int res = 0;
        //比较两个路径,找到第一个不同的点
        for(int i = 0; i < path_p.size() && i < path_q.size(); i++){ 
            int x = path_p.get(i);
            int y = path_q.get(i);
            //最后一个相同的节点就是最近公共祖先
            if(x == y) 
                res = path_p.get(i);
            else
                break;
        }
        return res;
    }
}

返回二叉树中 两个节点的最近公共祖先

二叉树,递归遍历每个节点,要求当前节点往左or右能够到达p,且往右or左能够到达q。否则往子树递归遍历。

    public int lowestCommonAncestor(TreeNode root, int o1, int o2) {
        return helper(root, o1, o2).val;
    }

    public TreeNode helper(TreeNode root, int o1, int o2) {
        if (root == null || root.val == o1 || root.val == o2)
            return root;
        TreeNode left = helper(root.left, o1, o2);
        TreeNode right = helper(root.right, o1, o2);
        //如果left为空,说明这两个节点在root结点的右子树上,我们只需要返回右子树查找的结果即可
        if (left == null)
            return right;
        //同上
        if (right == null)
            return left;
        //如果left和right都不为空,说明这两个节点一个在root的左子树上一个在root的右子树上,
        //我们只需要返回cur结点即可。
        return root;
    }

返回二叉树和为t的路径

回溯

import java.util.*;
import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int expectNumber) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if(root==null) return res;
        ArrayList<Integer> temp = new ArrayList<> ();
        _find(res, temp, expectNumber, root);
        return res;
    }

    static void _find(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> list,
                      int t, TreeNode root) {
        if (root.left == null && root.right == null) {
            if (root.val == t) {
                list.add(root.val);
                ArrayList<Integer> ls = new ArrayList<>(list);
                list.remove(list.size() - 1);
                res.add(ls);
                return ;
            }
            else return ;
        }
        if (root.left == null) {
            list.add(root.val);
            _find(res, list, t - root.val, root.right);
            list.remove(list.size() - 1);
            return ;
        }
        if (root.right == null) {
            list.add(root.val);
            _find(res, list, t - root.val, root.left);
            list.remove(list.size() - 1);
            return ;
        }

        list.add(root.val);
        _find(res, list, t - root.val, root.left);
        _find(res, list, t - root.val, root.right);
        list.remove(list.size() - 1);
    }
}

平衡二叉树判断

递归的判断左右子树是否平衡,平衡继续判断当前节点的左子树和右子树的高度差是否满足小于2要求。满足返回true,否则返回false。

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if (root == null) return true;
        //判断左子树和右子树是否符合规则,且深度不能超过2
        //先递归判断左子树 右子树 是否符合规则,否则判断当前节点的的左子树和右子树的高度差是否小于2
        return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right) && Math.abs(deep(root.left) - deep(root.right)) < 2;
    }
    
    //判断二叉树深度
    public int deep(TreeNode root) {
        if (root == null) return 0;
        return Math.max(deep(root.left), deep(root.right)) + 1;
    }
}

链表

复杂链表深拷贝

image-20220714173043585

import java.util.*;
/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if (pHead == null) return null;
        RandomListNode node =  pHead;
        RandomListNode head = null;
        RandomListNode temp = null;
        HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
        while (node != null) {
            if (head == null) {
                RandomListNode rn = new RandomListNode(node.label);
                head = rn;
                temp = rn;
                map.put(node, temp);
            } else {
                temp.next = new RandomListNode(node.label);
                map.put(node, temp.next);
                temp = temp.next;
            }
            node = node.next;
        }

        while (pHead != null) {
            if (pHead.random != null)
                map.get(pHead).random = map.get(pHead.random);
            pHead = pHead .next;
        }
        return head;
    }

}

递归回溯

n皇后

找到对角线数组与行、列号的关系。

import java.util.*;


public class Solution {
    /**
     *
     * @param n int整型 the n
     * @return int整型
     */
    static int count = 0;
    public int Nqueen (int n) {
        // write code here
        //记录行列 斜对角线是否摆放过
        boolean r [] = new boolean [n];
        boolean l [] = new boolean [n];

        //正对角线 n-j-1+i
        boolean tx[] = new boolean [2 * n - 1];
        //斜对角线 i+j
        boolean rx[] = new boolean [2 * n - 1];

        //放第一个
//         for (int i = 0; i < n; i++) 
            dfs(r, l, rx, tx, 0);
//         }
//         System.out.println(count);
        return count;
    }

    static void dfs(boolean r[], boolean l[], boolean rx[], boolean tx[],
                    int index) {
        if (index == r.length) {
            count++;
            return ;
        }

        int n = r.length;
        //试探第j列
        for (int j = 0; j < n; j++) {
            if (!r[index] && !l[j] && !tx[n - j - 1 + index] && !rx[index + j]) {
                r[index] = true;
                l[j] = true;
                tx[n - j - 1 + index] = true;
                rx[index + j] = true;
                
                dfs(r, l, rx, tx, index + 1);
                
                r[index] = false;
                l[j] = false;
                tx[n - j - 1 + index] = false;
                rx[index + j] = false;
            }
        }
    }

}

矩阵最长路径问题

给定矩阵求最长递增序列长度。起点终点不限,智能上下左右。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PYvX44xs-1690389890287)(https://s2.loli.net/2022/07/15/vkDchA2qdfSGeIK.png)]

递归

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 递增路径的最大长度
     * @param matrix int整型二维数组 描述矩阵的每个数
     * @return int整型
     */
    public int solve (int[][] matrix) {
        // write code here
        //深度优先搜索
        int dis = 0;
        boolean maze[][] = new boolean [matrix.length][matrix[0].length];
        int m = 0;
        int r = matrix.length;
        int l = matrix[0].length;

        for (int i = 0; i < r; i++) {
            for (int j = 0; j < l; j++) {
                m = Math.max(_dfs(i, j, maze, matrix) + 1, m);
            }
        }
        return m;
    }

    static int _dfs(int x, int y, boolean [][]maze, int matrix[][]) {
        int r = maze.length;
        int l = maze[0].length;
        int max = 0;
        maze[x][y] = true;
        int v = matrix[x][y];
        //右
        if (y < l - 1 && !maze[x][y + 1] && matrix[x][y + 1] > v) {
            max = Math.max(_dfs(x, y + 1, maze,matrix) + 1, max);
        }
        //下
        if (x < r - 1 && !maze[x + 1][y] && matrix[x + 1][y] > v) {
            max = Math.max(_dfs(x + 1, y, maze,matrix) + 1, max);
        }

        if (x > 0 && !maze[x - 1][y] && matrix[x - 1][y] > v) {
            max = Math.max(_dfs(x - 1, y, maze,matrix) + 1, max);
        }
        if (y > 0 && !maze[x][y - 1] && matrix[x][y - 1] > v) {
            max = Math.max(_dfs(x, y - 1, maze,matrix) + 1, max);
        }
        maze[x][y] = false;
        return max;
    }
}

dp优化,dp[x][y]表示从x,y开始所能拓展到的最长递增序列长度。当后面再次遍历到x,y节点可以直接返回。同时maze不需要,因为每一步都是也只能往高处走,不会往回走的情况。

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 递增路径的最大长度
     * @param matrix int整型二维数组 描述矩阵的每个数
     * @return int整型
     */
    public int solve (int[][] matrix) {
        // write code here
        //深度优先搜索
        //矩阵不为空
        if (matrix.length == 0 || matrix[0].length == 0)
            return 0;

//         boolean maze[][] = new boolean [matrix.length][matrix[0].length];
        int m = 0;
        int r = matrix.length;
        int l = matrix[0].length;
        int dp [][] = new int[r][l];

        for (int i = 0; i < r; i++) {
            for (int j = 0; j < l; j++) {
                m = Math.max(_dfs(i, j, matrix, dp), m);
            }
        }
        return m;
    }

    static int _dfs(int x, int y,  int matrix[][], int dp[][]) {
        //优化 减少递归
        if (dp[x][y] != 0) return dp[x][y];

        int r = matrix.length;
        int l = matrix[0].length;

        int max = 1;
        

        int v = matrix[x][y];
        //右
        if (y < l - 1 && matrix[x][y + 1] > v) {
            max = Math.max(_dfs(x, y + 1, matrix, dp) + 1, max);
        }
        //下
        if (x < r - 1  && matrix[x + 1][y] > v) {
            max = Math.max(_dfs(x + 1, y, matrix, dp) + 1, max);
        }

        if (x > 0  && matrix[x - 1][y] > v) {
            max = Math.max(_dfs(x - 1, y, matrix, dp) + 1, max);
        }
        if (y > 0  && matrix[x][y - 1] > v) {
            max = Math.max(_dfs(x, y - 1, matrix, dp) + 1, max);
        }
        //表示从dp[x][y] 拓展的最长递增子序列长度
        dp[x][y] = max;

        return max;
    }
}

贪心

活动安排

给定各个活动的开始结束时间,要求最大活动数量。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;


public class Main {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        //创建一个集合存储数据
        List<Node> xD = new ArrayList<Node>();

        Node node;

        for (int i = 0; i < n; i++) {
            //数据类型的起始值
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            node = new Node(a, b);
            //将活动对应的起始和结束时间加入集合
            xD.add(node);
        }

        //对活动时间进行排序,按照末尾时间从小到大的标准
        Collections.sort(xD, (o1, o2)-> {
            return o1.end - o2.end;
        });

        int begin = 0, count = 0;
        for (int i = 0; i < n; i++) {
            //当当前的起始值大于上一个活动的结束值时,符合要求
            if (xD.get(i).start >= begin) {
                //更新begin的值
                begin = xD.get(i).end;
                count++;
            }
        }
        System.out.println(count);
    }

}


//节点类
class Node {
    //该数据类型包含一个起始值,一个结束值,一个标记,
    int start;
    int end;
    public Node(int start, int end) {
        // TODO Auto-generated constructor stub
        this.start = start;
        this.end = end;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/796099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

客户体验:妙鸭相机(AI)与线下摄影的体验比较

Guofu 第 103⭐️ 篇原创文章分享 &#xff08;点击&#x1f446;&#x1f3fb;上方卡片关注我&#xff0c;加⭐️星标⭐️~&#xff09; &#x1f68f; 写在前面 最近 AI 的发展&#xff0c;每天都在刷新着我们的认知&#xff0c;人工智能已经渗透到我们生活的各个角落。其中&…

ssh2-sftp-client实现前端项目自动部署

首先要npm安装插件 npm i ssh2-sftp-client 项目中新建一个js文件 npm run build 之后在终端中 执行这个js文件就可以直接将文件上传到 服务器 import Client from ssh2-sftp-client; import { join } from path;const sftp new Client();const deploy async () > {try…

内存管理:判断对象是否存活

引用计数算法 引用计数算法&#xff08;Reference Counting&#xff09;判断对象是否存活的基本思路是&#xff1a;在对象中添加一个引用计数器&#xff0c;每当有一个地方引用该对象时&#xff0c;计数器的值就加一&#xff1b;当引用失效时&#xff0c;计数器的值就减一&…

Vector - CAPL - 诊断模块函数(TP层配置)

诊断TP层常见参数值 网络层定时参数的放置 常见的时间参数在诊断数据交互中的位置&#xff0c;后续会专门出一期关于ISO 15765-2的介绍。 CAPL对于此类函数介绍 CanTpGetTimeoutAr & CanTpGetTimeoutAr long CanTpGetTimeoutAr(long connHandle); long CanTpSetTimeoutAr(…

RabbitMQ 教程 | RabbitMQ 简介

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

充分了解java阻塞队列机制

多线程基础 1.阻塞队列1.1 什么是 阻塞队列1.2 阻塞队列的特点 1.3 阻塞队列常用方法1.3.1 抛出异常:add、remove、element1.3.2 返回结果但是不抛出异常offer、poll、peek1.3.3 阻塞put和take1.3.4 小结 1.4 常见的阻塞队列1.4.1 ArrayListBlockingQueue1.4.2 LinkedBlockingQ…

国标GB28181协议视频平台EasyCVR修改录像计划等待时间较长的原因排查与解决

音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、H.265自动转码H.264、平台级联等。为了便于用户二次开发、调用与集成&…

【PMP】有没有项目经理能看得懂这九张图?求挑战

这九张图&#xff0c;全是圈圈我的肺腑之言啊&#xff01;谁痛谁知道&#xff01; 做技术时&#xff0c;就想着30岁就转管理&#xff0c;管理岗位赚得多&#xff0c;结果发现全是烟雾弹。 做技术和代码打交道&#xff0c;做管理跟人打交道。天天开不完的会、说不完的话&#xf…

https证书怎么选择?

https证书即SSL数字证书&#xff0c;是遵守 SSL 协议的一种数字证书&#xff0c;由全球信任的证书颁发机构 (CA) 验证服务器身份后颁发&#xff0c;将 SSL 证书安装在网站服务器上&#xff0c;会激活挂锁和 https 协议。SSL 证书解决了网民登录网站的信任问题&#xff0c;网民可…

Java使用hive连接kyuubi

一、Maven依赖 <dependency><groupId>org.apache.hive</groupId><artifactId>hive-jdbc</artifactId><version>2.3.9</version> </dependency> 二、相关配置信息 驱动类&#xff1a;org.apache.hive.jdbc.HiveDriver连接UR…

HDMI接口需注意的PCB可制造性设计问题

高清多媒体接口(High Definition Multimedia Interface)简称HDMI&#xff0c;是一种全数字化视频和声音发送接口&#xff0c;可以同时发送未压缩的视频及音频信号&#xff0c;且发送时采用同一条线材&#xff0c;大大简化了系统线路的安装难度&#xff0c;所以应用非常广泛&…

ubuntu初始化/修改root密码

1.登录ubuntu后&#xff0c;使用sudo passwd root命令&#xff0c;进行root密码的初始化/修改&#xff0c;注&#xff1a;这里需要保证两次输入的密码都是同一个&#xff0c;才可成功 ubuntugt-ubuntu22-04-cmd-v1-0-32gb-100m:~/ocr$ sudo passwd root New password: Retype…

《2023中国开发者调查报告》探索2023中国开发者的技术创新与挑战:AIoT、云原生、国产数据库等领域的发展与前景

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

2023最新Windows安装配置Redis教程,嘎嘎详细

虽然 Redis 官方网站没有提供 Windows 版的安装包&#xff0c;但可以通过 GitHub 来下载 Windows 版 Redis 安装包&#xff0c;下载地址&#xff1a;https://github.com/tporadowski/redis/releases。 注意&#xff1a;Windows 安装包是某位民间“大神”根据 Redis 源码改造的&…

mybatisPlus之通用枚举及字段类型处理器

目录 通用枚举 为什么需要枚举类 EnumValue 具体使用 字段类型处理器 为什么需要字段类型处理器 具体使用 通用枚举 为什么需要枚举类 类的对象只有有限个&#xff0c;确定的。举例如下&#xff1a; 星期&#xff1a;Monday(星期一)、......、Sunday(星期天)性别&#x…

SentencePiece android ndk编译

LLaMa等LLM语言模型一般使用SentencePiece tokenizer&#xff0c;在端侧部署需要编译和使用其c版本。 在安卓平台使用NDK编译 CMakeLists.txt需要进行一些修改&#xff1a; src/CMakeLists.txt如下位置加上log依赖&#xff0c;否则提示android log相关符号不存在。 此外&…

【云原生技术】高效、灵活、易于使用的低代码快速开发平台源码

PaaS低代码快速开发平台是一种快速开发应用系统的工具&#xff0c;用户通过少量代码甚至不写代码就可以快速构建出各种应用系统。 随着信息化技术的发展&#xff0c;企业对信息化开发的需求正在逐渐改变&#xff0c;传统的定制开发已经无法满足企业需求。低代码开发平台&#x…

Michael.W基于Foundry精读Openzeppelin第13期——Checkpoints.sol

Michael.W基于Foundry精读Openzeppelin第13期——Checkpoints.sol 0. 版本0.1 Checkpoints.sol 1. 目标合约2. 代码精读2.1 History体系2.1.1 push(History storage self, uint256 value) && push(History storage self, function(uint256, uint256) view returns (uin…

Windows10下NI板卡驱动安装

文章目录 一. NI&#xff08;National Instruments 美国国家仪器有限公司&#xff09;介绍二. NI Package Manager软件说明 一. NI&#xff08;National Instruments 美国国家仪器有限公司&#xff09;介绍 官网地址: https://www.ni.com/zh-cn/solutions.html?category&…

基于SpringBoot+Vue的实习管理系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…