【迎战蓝桥】 算法·每日一题(详解+多解)-- day9

简介: 💖1. 两个链表的第一个公共结点💖2. 二叉树的深度💖3. 数组中只出现一次的数字

 

🤞目录🤞

💖1. 两个链表的第一个公共结点

💖2. 二叉树的深度

💖3. 数组中只出现一次的数字


【大家好,我是爱干饭的猿,如果喜欢这篇文章,点个赞👍,关注一下吧,后续会一直分享题目与算法思路


🌌1. 两个链表的第一个公共结点

描述

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:

image.gif编辑

可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

输入描述:

输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。

返回值描述:

返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。

解题思路:

🎈1. 思路一:题目要求是单链表,所以如果有交点,则最后一个链表的节点地址一定是相同的,求第一公共节点,而且两条链表相同的节点长度相同

1. 我们可以让较长的链表先往后走Math.abs(length1-length2)步,

2. 然后往后找第一个地址相同的节点(并且要保证两条链中该节点之后的所有节点值相同),就是题目要求的节点。

🎈2. 思路二:我们可以使用Map

1. 先将第一个单链表节点值全部加入到map集合

2. 然后遍历第二个单链表,将节点加入map中时,如果当前节点值已存在在map集合

3. 并且在此节点之后的节点值也都在map集合之中,也就是说该节点有极大可能性就是pHead1和pHead2的第一个公共结点。

🌈思路一:代码如下:  

// 方法一
    // 让较长的链先走k步,使得两条链长度相同,然会两条链同时向后走
    // 当遇到第一个相同节点时,该节点就是两个链表的第一个公共结点
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if(pHead1 == null || pHead2 == null){
            return null;
        }
        int length1 = getLength(pHead1);
        int length2 = getLength(pHead2);
        int step = Math.abs(length1 - length2);
        // 1. 使得较长的链先走step步
        if(length2 < length1){
            for (int i = 0; i < step; i++) {
                pHead1 = pHead1.next;
            }
        }else {
            for (int i = 0; i < step; i++) {
                pHead2 = pHead2.next;
            }
        }
        // 2. 找第一个地址相同的节点
        while (pHead1 != null && pHead2 != null){
            // 并且要保证两条链中该节点之后的所有节点值相同
            if(pHead1.val == pHead2.val && allContains(pHead1.next,pHead1.next)){
                return pHead1;
            }
            pHead1 = pHead1.next;
            pHead2 = pHead2.next;
        }
        return null;
    }
    // 保证两条链中该节点之后的所有节点值相同
    private boolean allContains(ListNode l1, ListNode l2) {
        while (l1 != null && l2 != null){
            if(l1.val != l2.val){
                return false;
            }
            l1 = l1.next;
            l2 = l2.next;
        }
        return true;
    }

image.gif

🌈思路二:代码如下:  

// 方法二
    // 用例8/9
    public ListNode FindFirstCommonNode2(ListNode pHead1, ListNode pHead2) {
        Map<Integer,Integer> map = new LinkedHashMap();
        // 1. 使用Map,先将第一个单链表节点值全部加入到map集合
        for(ListNode x = pHead1;x != null;x = x.next){
            map.put(x.val,1);
        }
        // 2. 然后遍历第二个单链表
        for(ListNode x = pHead2;x != null;x = x.next){
            // 将节点加入map中时,如果当前节点值已存在在map集合
            if(map.containsKey(x.val)){
                if(x.next != null){
                    // 3. 并且在此节点之后的节点值也都在map集合之中
                    if(allContainKey(map,x.next)){
                        // 该节点有极大可能性就是pHead1和pHead2的第一个公共结点
                        return x;
                    }
                }else {
                    return x;
                }
            }
        }
        return null;
    }
    // 判断此节点之后的节点值也都在map集合之中
    private boolean allContainKey(Map<Integer, Integer> map, ListNode x) {
        while (x != null){
            if(!map.containsKey(x.val)){
                return false;
            }
            x = x.next;
        }
        return true;
    }

image.gif


🌌2. 二叉树的深度

描述

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。

假如输入的用例为{1,2,3,4,5,#,6,#,#,7},那么如下图:

image.gif编辑

image.gif编辑

解题思路:

🎈1. 思路一:可以使用递归方式,当每次递时 + 1,递到叶子节点时归,取左右孩子归的最大值。

🎈2. 思路二:可以层序遍历,统计层数,也就是深度or高度

1. 设置一个队列,并将根节点入队

2. 如果队列不为空,就将当前队列中所有节点出队(将一层节点出队depth += 1)

3. 出队时将该节点的左右孩子入队

4. 当队列为空时,说明每层节点都进行了入队出队操作,depth 值就是树的深度

🌈思路一:代码如下:  

// 方法一 递归
    public int TreeDepth(TreeNode root) {
        // 递到叶子节点时归,
        if(root == null){
            return 0;
        }
        // 当每次递时 + 1,取左右孩子归的最大值
        return 1 + Math.max(TreeDepth(root.left),TreeDepth(root.right));
    }

image.gif

🌈思路二:代码如下:  

// 方法二 迭代
    public int TreeDepth2(TreeNode root) {
        if (root == null) {
            return 0;
        }
        // 1.设置一个队列,并将根节点入队
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int depth = 0;
        // 2. 如果队列不为空,当前队列中所有节点出队
        while (!queue.isEmpty()) {
            // (将一层节点出队depth+= 1)
            depth++;
            int size = queue.size();
            // 就将当前队列中所有节点出队
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                // 3. 出队时将该节点的左右孩子入队
                if(node.left != null) queue.offer(node.left);
                if(node.right != null) queue.offer(node.right);
            }
        }
        // 4. 走到这,说明当队列为空,每层节点都进行了入队出队操作,depth 值就是树的深度
        return depth;
    }

image.gif


🌌3. 数组中只出现一次的数字

描述

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

解题思路:

🎈1. 思路一:如果只有一个数据单独出现,直接整体异或得到结果,但是这道题是两个不重复的数据。

1. 我们可以采取先整体异或,异或结果一定不为0,而其中为1的比特位,不同的两个数据该 位置上的数据一定不同

2. 找到整体异或结果其中为1的比特位(只有两个单身数字异或结果有1的比特位)

3. 所以我们可以用该比特位进行分组,分组的结果一定是,相同数据被分到了同一组,不同数据一定被分到了不同的组,问题就转化成了两个问题一

🎈2. 思路二:使用map key-value键值对

1. 先设置一个map集合,并将所有元素加入map集合中,如果map中已存在该元素,使该value+1

2. 遍历map集合,其中value值为1 的元素就是单身元素

 🌈思路一:代码如下:

// 方法一 异或^
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int result = 0;
        // 1.将所有元素全部异或一遍
        // 得到的result就是两个只出现一次的异或结果
        for(int i = 0;i < array.length;i++){
            result ^= array[i];
        }
        // 2. 找到整体异或结果其中为1的比特位(只有两个单身数字异或结果有1的比特位)
        int flag = 1;
        while (true){
            if((flag & result) != 0){
                break;
            }
            flag <<= 1;
        }
        // 3. 所以我们可以用该比特位进行分组,分组的结果一定是,
        // 相同数据被分到了同一组,不同数据一定被分到了不同的组,问题就转化成了两个问题一
        for (int i = 0; i < array.length; i++) {
            if((flag & array[i]) == 1){
                num1[0] ^= array[i];
            }else {
                num2[0] ^= array[i];
            }
        }
    }

image.gif

 🌈思路二:代码如下:  

// 方法二 map
    public void FindNumsAppearOnce1(int [] array,int num1[] , int num2[]) {
        // 1. 先设置一个map集合,并将所有元素加入map集合中
        Map<Integer,Integer> map = new HashMap<>();
        for(int i : array){
            if(map.containsKey(i)){
                // 如果map中已存在该元素,使该value+1
                map.replace(i,map.get(i)+1);
            }else {
                map.put(i,1);
            }
        }
        // 2. 遍历map集合,其中value值为1 的元素就是单身元素
        int count = 0;
        for(int i : array){
            if(map.get(i) == 1){
                if(count == 0){
                    num1[0] = i;
                    count ++;
                }else {
                    num2[0] = i;
                }
            }
        }
    }
}

image.gif

相关文章
|
算法
单链表(算法面试题2)---单链表进阶2 一题多解,逐步优化
单链表(算法面试题2)---单链表进阶2 一题多解,逐步优化
40 0
|
1月前
|
存储 人工智能 算法
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
【算法——动态规划】蓝桥ALGO-1007 印章(C/C++)
|
1月前
|
算法 C++
蓝桥 算法训练 共线(C++)
蓝桥 算法训练 共线(C++)
|
6月前
|
存储 算法 安全
【数据结构与算法初学者指南】【冲击蓝桥篇】String与StringBuilder的区别和用法
【数据结构与算法初学者指南】【冲击蓝桥篇】String与StringBuilder的区别和用法
|
11月前
|
算法
|
11月前
|
算法 机器人
|
算法 测试技术
蓝桥算法_单词分析-wordAnalysis
蓝桥算法_单词分析-wordAnalysis
|
存储 算法
【备战蓝桥,冲击省一】高精度算法实现加减乘除
【备战蓝桥,冲击省一】高精度算法实现加减乘除
150 0
|
算法
【迎战蓝桥】 算法·每日一题(详解+多解)-- day11
💖1. 按之字形顺序打印二叉树 💖2. 二叉搜索树的第k个节点 💖3. 二叉搜索树的第k大节点
|
28天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。