文章目录

  • 二叉树相关
    • 965. 单值二叉树
    • 993. 二叉树的堂兄弟节点
    • 250 统计同值子树
  • 括号题目相关
    • 1541. 平衡括号字符串的最少插入次数
  • 二分搜索的泛化使用
    • 框架
    • 875. 爱吃香蕉的珂珂
    • 1011. 在 D 天内送达包裹的能力
  • 前缀和问题
  • 差分数组
    • 1109. 航班预订统计
    • 370.区间加法
    • 1094. 拼车

二叉树相关

965. 单值二叉树

965. 单值二叉树
要求每个节点值相同,相同返回true,反之返回false

二叉树解决方法,遍历框架:

void traverse(root){if(root == null) return;//前traverse(root.left);//中traverse(root.right);//后
}

定义两个全局变量,bool flag = true记录合规性,一旦出现false即返回;int val 记录根节点的值与其他节点比较。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {public:bool flag = true;int val;bool isUnivalTree(TreeNode* root) {if(root == nullptr) return true;val = root->val;traverse(root);return flag;}void traverse(TreeNode* root){// 发现节点为空或者flag== false的情况,即returnif(root == nullptr || !flag) return;if(root->val != val) {flag = false;return;}traverse(root->left);traverse(root->right);}
};

993. 二叉树的堂兄弟节点

在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。

如果二叉树的两个节点深度相同,但 父节点不同 ,则它们是一对堂兄弟节点。

我们给出了具有唯一值的二叉树的根节点 root ,以及树中两个不同节点的值 x 和 y 。

只有与值 x 和 y 对应的节点是堂兄弟节点时,才返回 true 。否则,返回 false。

题解:

二叉树问题无非就是“遍历” 和“分治”

这个问题应该使用遍历方法,确定返回true的条件为

  1. xy的父节点是不同的
  2. xy应位于同一层,即两者的深度相同。

所以,在遍历找到xy的同时将其父节点信息和深度信息一同记录

二叉树遍历的框架为

void traverse(root,参数){if(root == null) return;//前traverse(root.left);//中traverse(root.right);//后
}

此题中需要找到深度和父节点,参数中需要深度信息depth 和父节点TreeNode* parent

另外为找到xy的位置,要比较root->val所以在前序遍历位置写入。

解答如下:

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {public://定义几个全局变量//父节点、深度,x、y的值TreeNode* parentX = nullptr;TreeNode* parentY = nullptr;int depthX = 0, depthY = 0;int x, y;bool isCousins(TreeNode* root, int x, int y) {this->x = x;this->y = y;traverse(root, 0,nullptr);//父节点不同且深度相同即符合条件if(parentX != parentY && depthY == depthX){return true;}return false;}//输入 root 当前深度,父节点,记录相应值void traverse(TreeNode* root, int depth, TreeNode* parent){if(root == nullptr) return;//前序位置if(root->val == x) {//记录x 深度和父节点parentX = parent;depthX = depth;}if(root->val == y){//记录yparentY = parent;depthY = depth;}traverse(root->left, depth+1, root);traverse(root->right, depth+1, root);}
};

250 统计同值子树

题目描述

给定一个二叉树,统计该二叉树数值相同的子树个数。

同值子树是指该子树的所有节点都拥有相同的数值。

题目链接

因为要得到子树的相关信息,利用后序遍历得到子树的信息。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {public:int res = 0;int countUnivalSubtrees(TreeNode* root) {// 先保证父节点不为空if(root == nullptr) return 0;getUnivalue(root);return res;}// 输入一个节点// 如果是同值子树 返回true// 不是同值子树返回falsebool getUnivalue(TreeNode* root){if(root == nullptr) return true;bool left = getUnivalue(root->left);bool right = getUnivalue(root->right);//后序遍历位置// 已经得到子树信息if(root->left && root->val != root->left->val){return false;}if(root->right && root->val != root->right->val){return false;}if(right && left){res++;return true;}return false;}
};

括号题目相关

1541. 平衡括号字符串的最少插入次数

1541. 平衡括号字符串的最少插入次数

给你一个括号字符串 s ,它只包含字符 ‘(’ 和 ‘)’ 。一个括号字符串被称为平衡的当它满足:

  • 任何左括号 ‘(’ 必须对应两个连续的右括号 ‘))’ 。
  • 左括号 ‘(’ 必须在对应的连续两个右括号 ‘))’ 之前。
    比方说 “())”, “())(())))” 和 “(())())))” 都是平衡的, “)()”, “()))” 和 “(()))” 都是不平衡的。

你可以在任意位置插入字符 ‘(’ 和 ‘)’ 使字符串平衡。

请你返回让 s 平衡的最少插入次数。

题解:

这个问题主要在处理细节上,用need表示需要的右括号数量,res表示需要的左括号数量,返回结果:res + need

处理的细节:

  • 遍历至左括号,按规则右括号need += 2,但要检查此时是否为奇数。奇数情况说明添加左括号即可,使need--;res++;
  • 遍历至右括号,按规则need--,但也要检查need == -1,-1时说明缺少左括号,使res++同时need= 1
class Solution {public:int minInsertions(string s) {//need代表需要几个右括号// res 表示过程中要加的左括号//返回res+needint need = 0;int res = 0;for(char c : s){if(c == '('){need += 2;if(need % 2 == 1){//单数情况下,得添加左括号,另need--need--;res++;}}if(c == ')'){need--;if(need == -1){res++;need = 1;}}}return need + res;}
};

二分搜索的泛化使用

框架

一般的二分搜索是求有序数组中的元素

泛化场景下,一般存在一个f(x)的单调函数,求其中的左右边界。

代码框架如下:

// 函数 f 是关于自变量 x 的单调函数
int f(int x) {// ...
}// 主函数,在 f(x) == target 的约束下求 x 的最值
int solution(int[] nums, int target) {if (nums.length == 0) return -1;// 问自己:自变量 x 的最小值是多少?int left = ...;// 问自己:自变量 x 的最大值是多少?int right = ... + 1;while (left < right) {int mid = left + (right - left) / 2;if (f(mid) == target) {// 问自己:题目是求左边界还是右边界?// ...} else if (f(mid) < target) {// 问自己:怎么让 f(x) 大一点?// ...} else if (f(mid) > target) {// 问自己:怎么让 f(x) 小一点?// ...}}return left;
}

875. 爱吃香蕉的珂珂

875. 爱吃香蕉的珂珂

珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。
珂珂可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 H 小时内吃掉所有香蕉的最小速度 K(K 为整数)。

此题就存在一个单调递减的f(x)函数,x是吃香蕉的速度,f(x)为所用的时间。

寻找的是f(x) = H的最小x

代码如下:

class Solution {public:int minEatingSpeed(vector<int>& piles, int h) {int lo = 1;//最小值一小时一根香蕉int hi = 1000000000 + 1;//最大值,题目限定的最大值+1// int hi = 1; //或者求最大值,因为一次只会选择一堆吃// for(int banna : piles){//    hi = max(hi, banna);// }while(lo < hi){int mid = lo + (hi - lo) / 2;//求解的是最小速度,求得是左边界,返回loif(f(piles, mid) <= h){hi = mid;//f(x)小了,要让x变小,让右边界缩}else{// 加1是因为mid已经计算不等于h,所以舍去lo = mid+1;//f(x)大了,要让x变大,让左边界缩,}} return lo;}//二分法需要列出f(x),// 定义速度为x,需要f(x)小时吃完香蕉int f(vector<int>& piles, int x){int hours = 0;for(int i = 0; i < piles.size(); ++i){//一次选择一堆,计算每一堆的时间hours += piles[i] / x;if(piles[i] % x != 0){hours++;//无法整除,说明堆中剩下的不足x个,加1小时}}return hours;}
};

1011. 在 D 天内送达包裹的能力

1011. 在 D 天内送达包裹的能力

传送带上的包裹必须在 days 天内从一个港口运送到另一个港口。
传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量(weights)的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。
返回能在 days 天内将传送带上的所有包裹送达的船的最低运载能力。

还是按照上面的套路,f(x)是载重量为x时完成运输的天数,还是单调递减。

处理f(x)的细节上略有不同,但二分搜索的框架仍不变

class Solution {public:int shipWithinDays(vector<int>& weights, int days) {int lo = 1;int hi = 1;// 因为是传送带可以一直运输,重量是每个包裹的重量且不可拆分// 最小lo应是最大包裹重量,包裹不能拆,不然运不走// 最大hi应是所有包裹重量,一天运走for(auto w : weights){lo = max(lo, w);hi += w;}// 求能够运完的最小速度,求得是左边界,返回lowhile(lo < hi){int mid = lo + (hi - lo) / 2;if(f(weights, mid) <= days){hi = mid;}else{lo = mid+1;}}return lo;}// 二分法求极值// 首先定义f(x):运载能力在x时,需要f(x)天运送完成int f(vector<int>& weights, int x){int days = 0;// 前提:只要船没有装满就可以一直装for(int i = 0; i < weights.size(); ){int cap = x;while(i < weights.size()){if(cap < weights[i]) break;// 装不下这个包裹了,跳出while,天数加1,cap重新计算else cap -= weights[i];i++;}days++;}return days;}
};

前缀和问题

应用前缀和的场景,前缀和主要适用的场景是原始数组不会被修改的情况下,频繁查询某个区间的累加和。

差分数组

与前缀和思想非常类似的算法技巧「差分数组」,但和前缀和有所不同,差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减。

一般场景:
给定一个数组,要求在[i1, j1]内加val1,在[i2, j2]内加val2,在[i3, j3]内加val3…求最后的数组

常规思路会按照模拟去频繁访问数组修改,效率较低。

差分数组工具类:

class Difference {private://差分数组vector<int> diff;public://构造差分数组void difference(vector<int> nums){if(nums.size() > 0){diff.resize(nums.size());diff[0] = nums[0];for(int i = 1; i < nums.size(); i++){diff[i] = nums[i] - nums[i-1];}}}//给[i,j]的闭区间上加上val,val可以是负数void increament(int i, int j, int val){diff[i] += val;if(j + 1 < diff.size()){diff[j+1] -= val;}}//返回结果数组vector<int> getResult(){vector<int> ans(diff.size());ans[0] = diff[0];for(int i = 1; i < diff.size(); i++){ans[i] = diff[i]+ ans[i-1];}return ans;}
};

1109. 航班预订统计

1109. 航班预订统计
这里有 n 个航班,它们分别从 1 到 n 进行编号。

有一份航班预订表 bookings ,表中第 i 条预订记录 bookings[i] = [firsti, lasti, seatsi] 意味着在从 firsti 到 lasti (包含 firsti 和 lasti )的 每个航班 上预订了 seatsi 个座位。

请你返回一个长度为 n 的数组 answer,里面的元素是每个航班预定的座位总数。

    vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {//初始化vector<int> nums(n,0);// 新建差分工具对象Difference df = Difference();df.difference(nums);/* i = books[0]-1;j = books[1]-1;val = books[2];*/for(auto books : bookings){df.increament(books[0]-1, books[1]-1, books[2]);}return df.getResult();}

370.区间加法

370.区间加法
假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k​​​​​​​ 个更新的操作。

其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndex … endIndex](包括 startIndex 和 endIndex)增加 inc。

请你返回 k 次操作后的数组。

vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {// 初始化数组vector<int> nums(length, 0);// df工具类对象Difference df = Difference();df.difference(nums);/*i = update[0]j = update[1]val = update[2]*/for(auto update : updates){df.increament(update[0],update[1], update[2]);}return df.getResult();
}

1094. 拼车

1094. 拼车

假设你是一位顺风车司机,车上最初有 capacity 个空座位可以用来载客。由于道路的限制,车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向,你可以将其想象为一个向量)。

这儿有一份乘客行程计划表 trips[][],其中 trips[i] = [num_passengers, start_location, end_location] 包含了第 i 组乘客的行程信息:

必须接送的乘客数量;
乘客的上车地点;
以及乘客的下车地点。
这些给出的地点位置是从你的 初始 出发位置向前行驶到这些地点所需的距离(它们一定在你的行驶方向上)。

请你根据给出的行程计划表和车子的座位数,来判断你的车是否可以顺利完成接送所有乘客的任务(当且仅当你可以在所有给定的行程中接送所有乘客时,返回 true,否则请返回 false)。

    bool carPooling(vector<vector<int>>& trips, int capacity) {// 初始化数组vector<int> nums(1001, 0);// 差分工具对象Difference df = Difference();df.difference(nums);/*i = trip[1] 该站上车j = trip[2]-1 该站就下车了,所以不计入人数val = trip[0] 人数*/for(auto trip : trips){df.increament(trip[1],trip[2]-1, trip[0]);}vector<int> ans = df.getResult();// 判断结果         for(int a : ans){if(a > capacity){return false;}}return true;}

LeetCode刷题记录相关推荐

  1. LeetCode刷题记录15——21. Merge Two Sorted Lists(easy)

    LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) 目录 LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) ...

  2. LeetCode刷题记录14——257. Binary Tree Paths(easy)

    LeetCode刷题记录14--257. Binary Tree Paths(easy) 目录 前言 题目 语言 思路 源码 后记 前言 数据结构感觉理论简单,实践起来很困难. 题目 给定一个二叉树, ...

  3. LeetCode刷题记录13——705. Design HashSet(easy)

    LeetCode刷题记录13--705. Design HashSet(easy) 目录 LeetCode刷题记录13--705. Design HashSet(easy) 前言 题目 语言 思路 源 ...

  4. LeetCode刷题记录12——232. Implement Queue using Stacks(easy)

    LeetCode刷题记录12--232. Implement Queue using Stacks(easy) 目录 LeetCode刷题记录12--232. Implement Queue usin ...

  5. LeetCode刷题记录11——290. Word Pattern(easy)

    LeetCode刷题记录11--290. Word Pattern(easy) 目录 LeetCode刷题记录11--290. Word Pattern(easy) 题目 语言 思路 源码 后记 题目 ...

  6. LeetCode刷题记录10——434. Number of Segments in a String(easy)

    LeetCode刷题记录10--434. Number of Segments in a String(easy) 目录 LeetCode刷题记录9--434. Number of Segments ...

  7. LeetCode刷题记录9——58. Length of Last Word(easy)

    LeetCode刷题记录9--58. Length of Last Word(easy) 目录 LeetCode刷题记录9--58. Length of Last Word(easy) 题目 语言 思 ...

  8. LeetCode刷题记录8——605. Can Place Flowers(easy)

    LeetCode刷题记录8--605. Can Place Flowers(easy) 目录 LeetCode刷题记录8--605. Can Place Flowers(easy) 题目 语言 思路 ...

  9. LeetCode刷题记录7——824. Goat Latin(easy)

    LeetCode刷题记录7--824. Goat Latin(easy) 目录 LeetCode刷题记录7--824. Goat Latin(easy) 题目 语言 思路 后记 题目 题目需要将一个输 ...

  10. LeetCode刷题记录6——696. Count Binary Substrings(easy)

    LeetCode刷题记录6--696. Count Binary Substrings(easy) 目录 LeetCode刷题记录6--696. Count Binary Substrings(eas ...

最新文章

  1. Hbase的过滤器查询
  2. 嵌入式 自旋锁、互斥锁、读写锁、递归锁
  3. Windows下的常用的DOS命令
  4. 关于APK文件反编译方法(图文详解)
  5. Linux内核分析-孟宁
  6. 最多添加3个标签,每个标签最长6字,空格或逗号隔开
  7. ROS 启动自带摄像头或者USB摄像头
  8. 半监督学习入门基础(二):最基础的3个概念
  9. C++ {}作用域 return
  10. java中reg=new,JavaScript replace new RegExp使用介绍
  11. python 入门教程
  12. excel服务器 微信设置,微信电脑版excel怎么编辑
  13. 区块链基础知识的归纳与总结
  14. 在yandex投放广告的话,需要注册俄罗斯常用的域名吗?
  15. 皮皮虾视频分析并加工
  16. 中移物联网在车联网场景的 TiDB 探索和实现
  17. 酷博社区卫生系统激活健康档案的生命活力
  18. 相机标定中的相机焦距
  19. [UE4] LogicDriver状态机盒体颜色切换简单案例
  20. UGUI优化:使用镜像图片

热门文章

  1. python多元回归分析_多变量分析:多元回归分析
  2. COMSOL中场路耦合(电路接口与电磁场接口)
  3. 数字信号处理实验4:用窗口法设计FIR滤波器
  4. 手机双清,三清,四清,五清,六清介绍
  5. Learning Shape Representations for Clothing Variations in Person Re-Identification
  6. 前端sku-spu详解
  7. 抖音如何能快速涨粉?
  8. c语言程序输入自己班级学号,C语言中设计一个程序就是通过输入学号就能知道班级的程序...
  9. 光速虚拟机手机谷歌服务器,光速虚拟机一款安卓上的模拟器,在安卓手机里再装一个安卓系统...
  10. linux服务器配置免密登录方式(vscode 以及 MobaXterm 登录)