程序笔记   发布时间:2022-07-12  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了2021-08-24 力扣刷题笔记大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

每日一题787. K 站中转内最便宜的航班题目描述解题思路Bellman Ford一、617. 合并二叉树题目描述解题思路二、116. 填充每个节点的下一个右侧节点指针题目描述解题思路 方法一解题思路 方法二
TOC

每日一题787. K 站中转内最便宜的航班

题目描述

有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 toi 抵达 pricei。

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1。

示例 1:

输入:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
输出: 200

示例 2:

输入:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
输出: 500
解题思路

今天的每日一题是我不熟悉的图论的问题,根据三宫姐姐的思路使用Bellman Ford + 邻接矩阵来解题,那么这个Bellman Ford是什么呢

Bellman Ford

Bellman-Ford 算法是用来处理单源最短路径的一种算法,它可以处理Dijkstra算法处理不了的图中权值有负值的情况。

它的主要思想是对所有的边进行n - 1轮的松弛操作,因为在一个含有n个顶点的图中,任意两点之间的最短路径最多包含 n - 1 条边。也就是说在所有的边经历第1轮松弛操作后,得到的是原点最多经过一条边到达其他顶点的最短距离;在所有的边经历第2轮松弛操作后,得到的是原点最多经过两条边到达其他顶点的最短距离;在所有的边经历第3轮松弛操作后,得到的是原点最多经过三条边到达其他顶点的最短距离,依次类推,在所有的边经历第n - 1轮松弛操作后,得到的是原点最多经过 n - 1条边也就是除了它本身之外的所有边到达其他顶点的最短距离。

松弛操作是指如果原点s到某个顶点v的距离大于原点s到某个顶点u的距离加上u到v的距离,那就把原点s到某个顶点v的距离置为原点s到某个顶点u的距离加上u到v的距离。数字形式为Distance(v) > Distance(u) + w(u, v),其中Distance(v)代表原点到v的距离,w(u, v)代表u到v的距离。

因此Bellman-Ford 算法的核心代码为

int src;// 原点
int[][] edges;// 使用邻接矩阵存储所有边的权重
int[] distance;// 存储原点到其余点的距离估值;

Arrays.fill(distance, INF); // 初始化原点到其他点的距离为无限大
distance[src] = 0;// 初始化原点到原点的距离为0;
for(int i = 0; i < n; i++){ // n 为顶点的个数, 因此i为某个顶点
    for(int j = 0; j < n; j++){
        // edges[i][j] 为 i 到 j 的一条边;
        // 松弛操作
        if(distance[i] > distance[j] + edges[i][j];)
            distance[i] = distance[j] + edges[i][j];
    }
}

代码实现

class Solution {
     int n = 110; // 最多为100个顶点
     int INF = 0x3f3f3f3f; // 无穷大量
     int[][] edge = new int[n][n]; // 存储边的权重的邻接矩阵
     int[] dist = new int[n]; // 存储原点到顶点的距离
     int n; // n个顶点
     int s; // 原点
     int t; // 目的地
     int k; // 最多经历k - 1个中转站,也就是最多经历k条边
     public int findCheapestPrice(int _n, int[][] flights, int _src, int _dst, int _k) {
         n = _n;
         s = _src;
         t = _dst;
         k = _k + 1;
         for(int i = 0; i < N; i++){
             for(int j = 0; j < N; j++){
                 edge[i][j] = i == j ? 0 : INF; // 初始化所有的边为无穷
             }
         }
         for(int[] f : flights){// 将题目中给的条件放到邻接矩阵中 flights = [[起点,终点,权重],[1,2,100],[0,2,500]]
             int src = f[0]; // 起点
             int dst = f[1]; // 终点
             int wight = f[2]; // 权重(距离)
             edge[src][dst] = f[wigth];
         }
         int ans = bf(); // 执行Bellman Ford算法,得到最短距离
         return ans > INF / 2 ? -1 : ans; // 如果不存在这样的边则返回-1
     }
     int bf() {
         Arrarys.fill(dist, INF); // 初始化原点到其他顶点的距离为INF
         dist[s] = 0; // 初始化原点到原点的距离为0
         for(int limit = 0; limit < k; limit++){// 限制最多经历k条边
             int[] clone = dist.clone(); // 保存每轮松弛操作的结果
             for(int i = 0; i < n; i++){// 遍历n个顶点
                 for(int j = 0; j < n; j++){// 遍历所有的边
                     dist[i] = Math.min(dist[i], clone[j] + edge[i][j]); // 松弛操作;
                 }
             }
             return dist[t]; // 返回原点到目的地的最短距离
         }
}

一、617. 合并二叉树

题目描述

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

输入:
    Tree 1                     Tree 2                 
          1                         2                            
         /                        /                            
        3   2                     1   3                       
       /                                                   
      5                             4   7                 
输出:
合并后的树:
         3
        / 
       4   5
      /    
     5   4   7
解题思路

简单的深度优先搜索,合并就完事了

代码实现

/**
* Definition for a binary tree node.
* public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
* }
*/
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null || root2 == null)
            return root1 == null ? root2 : root1;
        dfs(root1, root2);
        return root1;
    }
    TreeNode dfs(TreeNode root1, TreeNode root2){
        if(root1 == null || root2 == null)
            return root1 == null ? root2 : root1;
        root1.val = root1.val + root2.val;
        root1.left = dfs(root1.left, root2.left);
        root1.right = dfs(root1.right, root2.right);
        return root1;
    }
}

二、116. 填充每个节点的下一个右侧节点指针

题目描述

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

例:

2021-08-24 力扣刷题笔记

输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。
解题思路 方法一

广度优先搜索,使用一个队列来存储每一层的节点,然后将节点进行链接

代码实现

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        if(root == null) return null;

        Queue<Node> queue = new LinkedList<>();
        queue.add(root); // 将根节点放入队列中

        while(!queue.isEmpty()){ // 逐层遍历
            int size = queue.size(); // 保存一下当前队列的长度,因为下面会将队列中的结点弹出,所以要提前保存
            for(int i = 0; i < size; i++){ // 遍历队列中的节点
                if(i < size - 1){ // 链接
                    Node node = queue.poll();
                    node.next = queue.peek();
                }
                if(node.left != null){
                    queue.add(node.left);
                }
                if(node.right != null){
                    queue.add(node.right);
                }
            }
        }
        return root;
    }
}
解题思路 方法二

类似深度优先搜索的递归,将当前节点的左右子节点链接,不会解释,看代码结合图理解吧

2021-08-24 力扣刷题笔记

实现代码

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        return root;
    }
    Node dfs(Node root){
        if(root == null) return null;

        Node left = root.left;
        Node right = root.right;

        while(left != null){ // 链接并且换节点
            left.next = right; // 同一个父节点的两个节点
            left = left.right; // 到了隔壁节点了
            right = right.left;
        }
        dfs(root.left);
        dfs(root.right);

        return root;
    }
}

大佬总结

以上是大佬教程为你收集整理的2021-08-24 力扣刷题笔记全部内容,希望文章能够帮你解决2021-08-24 力扣刷题笔记所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。