【Leetcode刷题记录】1、买钢笔和铅笔的方案数;2、一个图中连通三元组的最小度数;3、带因子的二叉树

发布时间 2023-09-01 15:36:04作者: Archigenius

1、买钢笔和铅笔的方案数

题目:给你一个整数 total ,表示你拥有的总钱数。同时给你两个整数 cost1 和 cost2 ,分别表示一支钢笔和一支铅笔的价格。你可以花费你部分或者全部的钱,去买任意数目的两种笔。

请你返回购买钢笔和铅笔的 不同方案数目 。

思路:枚举法。

假设 total 最多可以买 n 支钢笔,则令 i = 0 ... n 枚举购买 i 支钢笔剩下的钱最多可以买多少支铅笔。此时公式为 j =  (total - cost1 * i) / cost2。则当购买 i 支钢笔时,一共有 j + 1 种方案。

 1 class Solution {
 2 public:
 3     long long waysToBuyPensPencils(int total, int cost1, int cost2) {
 4         long long res = 0;
 5         int cnt = 0;
 6         while(cost1 * cnt <= total) {
 7             res += (total - cost1 * cnt) / cost2 + 1;
 8             cnt++;
 9         }
10         return res;
11     }
12 };

 

2、一个图中连通三元组的最小度数

题目:给你一个无向图,整数 n 表示图中节点的数目,edges 数组表示图中的边,其中 edges[i] = [ui, vi] ,表示 ui 和 vi 之间有一条无向边。

一个 连通三元组 指的是 三个 节点组成的集合且这三个点之间 两两 有边。

连通三元组的度数 是所有满足此条件的边的数目:一个顶点在这个三元组内,而另一个顶点不在这个三元组内。

请你返回所有连通三元组中度数的 最小值 ,如果图中没有连通三元组,那么返回 -1 。

思路:遍历所有的连通三元组

创建一个二维 vector 数组记录节点的无向边,创建一个一维 vector 数组记录节点的度(即该节点有几条无向边)。

从小到大遍历所有节点计算每个连通三元组的度数,具体的做法是:假设三元组的节点分别是 i 、j 、k,则这个三元组的度数就是 i 、j、 k的度数和减去 6(6是构成三元组的边数,三条边每条都乘2)

代码:C++

 1 class Solution {
 2 public:
 3     int minTrioDegree(int n, vector<vector<int>>& edges) {
 4         vector<vector<int>> index(n+1,vector<int>(n+1,0));
 5         vector<int> degree(n+1,0);
 6         for(auto const& edge : edges){
 7             int x = edge[0], y = edge[1];
 8             index[x][y] = 1;    //无向边
 9             index[y][x] = 1;
10             ++degree[x];        //每个节点的度数 +1
11             ++degree[y];
12         }
13         int res = edges.size();
14         //遍历每个连通三元组
15         for(int i = 1; i < n; ++i) {
16             for(int j = i + 1; j <= n; ++j) {
17                 if(index[i][j] == 1){
18                     for(int k = j + 1; k <=n; ++k){
19                         if(index[i][k] == 1 && index[j][k] == 1){
20                             res = min(res,degree[i]+degree[j]+degree[k] - 6);
21                         }
22                     }
23                 }
24             }
25         }
26         return res == edges.size() ? -1 : res;
27     }
28 };

 

3、带因子的二叉树

题目:给出一个含有不重复整数元素的数组 arr ,每个整数 arr[i] 均大于 1。

用这些整数来构建二叉树,每个整数可以使用任意次数。其中:每个非叶结点的值应等于它的两个子结点的值的乘积。

满足条件的二叉树一共有多少个?答案可能很大,返回109 + 7 取余 的结果。

思路:动态规划。双指针。

先将 arr 数组排序,因为每个节点的子结点一定要比自身小!

然后动态规划计算以每个节点作为根节点时,共有多少种二叉树。具体的做法是:假设以第 i 个节点作为根节点,那么则从 [0 ... i-1] 找到两个节点,使得两个节点的值的乘积等于 该节点的值;

然后做一次判断,如果这两个节点相等,则作为左右子结点不能互换,如果这两个节点不相等,则作为左右子结点可以互换。

代码:C++

 1 class Solution {
 2 public:
 3     int numFactoredBinaryTrees(vector<int>& arr) {
 4         sort(arr.begin(),arr.end());
 5         int n = arr.size();
 6         vector<long long> dp(n,1);
 7         long long res = 0, mod = 1e9 + 7;   //防止res过节,预先设置为long long类型
 8         for(int i = 0; i < n; ++i){
 9             for(int left = 0, right = i - 1; left <= right; ++left){
10                 while(left <= right && static_cast<long long>(arr[left]) * static_cast<long long>(arr[right]) > arr[i]){
11                     right--;
12                 }
13                 if(left <= right && arr[left] * arr[right] == arr[i]){
14                     if(left == right){
15                         dp[i] += (dp[left] * dp[right]) % mod;
16                     } else {
17                         dp[i] += (dp[left] * dp[right] * 2) % mod;
18                     }
19                 }
20             }
21             res = (res + dp[i]) % mod;
22         }
23         return res;
24     }
25 };