目录
主要思路:
经典广度优先搜索,基于队列;
对于本题需要将同一层的节点放在一个数组中,因此遍历的时候需要用一个变量 nums 来记录当前层的节点数,即 nums 等于队列元素的数目;
- #include
- #include
- #include
-
- 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:
- std::vector
int>> levelOrder(TreeNode* root) { - std::vector
int>> res; - if(root == nullptr) return res;
- std::queue
q; - q.push(root);
- while(!q.empty()){
- int nums = q.size(); // 当前层的节点数
- std::vector<int> tmp;
- while(nums > 0){ // 遍历处理同一层
- TreeNode *cur = q.front();
- q.pop();
- tmp.push_back(cur->val);
-
- if(cur->left != nullptr) q.push(cur->left);
- if(cur->right != nullptr) q.push(cur->right);
-
- nums--;
- }
- res.push_back(tmp); // 记录当前层的元素
- }
- return res;
- }
- };
-
- int main(int argc, char* argv[]){
- // root = [1, null, 2, 3]
- TreeNode *Node1 = new TreeNode(3);
- TreeNode *Node2 = new TreeNode(9);
- TreeNode *Node3 = new TreeNode(20);
- TreeNode *Node4 = new TreeNode(15);
- TreeNode *Node5 = new TreeNode(7);
- Node1->left = Node2;
- Node1->right = Node3;
- Node3->left = Node4;
- Node3->right = Node5;
-
- Solution S1;
- std::vector
int>> res = S1.levelOrder(Node1); - for(auto item : res) {
- for (int v : item) std::cout << v << " ";
- std::cout << std::endl;
- }
- return 0;
- }
主要思路:
递归计算左右子树的深度,选取两者最大值 +1 返回;
- #include
- #include
- #include
-
- 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 maxDepth(TreeNode* root) {
- if(root == nullptr) return 0;
- int res = dfs(root);
- return res;
- }
-
- int dfs(TreeNode* root){
- if(root == nullptr) return 0;
- int left_height = dfs(root->left);
- int right_height = dfs(root->right);
- int cur_height = std::max(left_height, right_height) + 1;
- return cur_height;
- }
- };
-
- int main(int argc, char* argv[]){
- // root = [3,9,20,null,null,15,7]
- TreeNode *Node1 = new TreeNode(3);
- TreeNode *Node2 = new TreeNode(9);
- TreeNode *Node3 = new TreeNode(20);
- TreeNode *Node4 = new TreeNode(15);
- TreeNode *Node5 = new TreeNode(7);
-
- Node1->left = Node2;
- Node1->right = Node3;
- Node3->left = Node4;
- Node3->right = Node5;
-
- Solution S1;
- int res = S1.maxDepth(Node1);
- std::cout << res << std::endl;
- return 0;
- }
主要思路:
思路类似于根据中序和后序遍历来构建二叉树;
对于本题,前序遍历的顺序是:根→左→右,则前序遍历的第一个节点是根节点;
中序遍历的顺序是:左→根→右,遍历中序数组找到根节点的位置,根据根节点的位置划分左右子树;
根据左右子树的大小划分前序遍历得到前序遍历的左右子树,递归构建左右子树即可;
- #include
- #include
- #include
-
- 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:
- TreeNode* buildTree(std::vector<int>& preorder, std::vector<int>& inorder) {
- TreeNode* res = dfs(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1);
- return res;
- }
-
- TreeNode* dfs(std::vector<int>& preorder, int p_st, int p_en, std::vector<int>& inorder, int i_st, int i_en){
- if(p_st > p_en || i_st > i_en){
- return nullptr;
- }
-
- // 头结点
- TreeNode *root = new TreeNode(preorder[p_st]);
- // 划分中序
- int pos = -1; // 中序遍历中根节点的位置索引
- for(int i = i_st; i <= i_en; i++){
- if(inorder[i] == root->val){
- pos = i;
- break;
- }
- }
- // 左子树的大小
- int left_size = pos - i_st;
- // 右子树的大小
- int right_size = i_en - pos;
-
- root->left = dfs(preorder, p_st+1, p_st+left_size, inorder, i_st, pos-1);
- root->right = dfs(preorder, p_st+left_size+1, p_en, inorder, pos+1, i_en);
- return root;
- }
- };
-
- int main(int argc, char* argv[]){
- // preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
- std::vector<int> preorder = {3, 9, 20, 15, 7};
- std::vector<int> inorder = {9, 3, 15, 20, 7};
-
- Solution S1;
- TreeNode* res = S1.buildTree(preorder, inorder);
-
- // 层次遍历打印
- std::queue
q; - q.push(res);
- while(!q.empty()){
- TreeNode* tmp = q.front();
- q.pop();
- std::cout << tmp->val << " ";
- if(tmp->left != nullptr) q.push(tmp->left);
- if(tmp->right != nullptr) q.push(tmp->right);
- }
- std::cout << std::endl;
- return 0;
- }
主要思路:
根据前序遍历的顺序,遍历二叉树,使用一个指针表示当前遍历到的节点的前驱节点,例如图中 2 的前驱节点是 1,4 的前驱节点是 3(根据前序遍历);
将前驱节点的左孩子为 nullptr,右孩子为当前遍历到的节点;根据前序遍历的顺序,递归更新前驱节点、左孩子和右孩子即可;
- #include
- #include
- #include
-
- 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:
- void flatten(TreeNode* root) {
- dfs(root);
- }
-
- void dfs(TreeNode* cur){
- if(cur == nullptr) return;
- pre->left = nullptr; // 前驱节点的左孩子指向 nullptr
- // 根
- pre->right = cur; // 前驱节点的右孩子指向当前遍历到的节点
- pre = cur; // 更新前驱节点
-
- TreeNode* left = cur->left;
- TreeNode* right = cur->right;
-
- dfs(left); // 递归处理左子树
- dfs(right); // 递归处理右子树
- }
- private:
- TreeNode* pre = new TreeNode(-1); // 前序遍历的前驱节点
- };
-
- int main(int argc, char* argv[]){
- // root = [1,2,5,3,4,null,6]
- TreeNode* Node1 = new TreeNode(1);
- TreeNode* Node2 = new TreeNode(2);
- TreeNode* Node3 = new TreeNode(5);
- TreeNode* Node4 = new TreeNode(3);
- TreeNode* Node5 = new TreeNode(4);
- TreeNode* Node6 = new TreeNode(6);
-
- Node1->left = Node2;
- Node1->right = Node3;
- Node2->left = Node4;
- Node2->right = Node5;
- Node3->right = Node6;
-
- Solution S1;
- S1.flatten(Node1);
- TreeNode* tmp = Node1;
- while(tmp -> right != nullptr){
- std::cout << tmp->val << " ";
- tmp = tmp->right;
- }
- std::cout << std::endl;
- return 0;
- }
主要思路:
计算截止到第 i 天的最低买入价格和最高的利润,不断更新即可;
- #include
- #include
-
- class Solution {
- public:
- int maxProfit(std::vector<int>& prices) {
- int min_cost = prices[0];
- int max_profit = 0;
- for(int i = 0; i < prices.size(); i++){
- min_cost = std::min(min_cost, prices[i]);
- max_profit = std::max(max_profit, prices[i] - min_cost);
- }
- return max_profit;
- }
- };
-
- int main(int argc, char *argv[]) {
- // [7, 1, 5, 3, 6, 4]
- std::vector<int> test = {7, 1, 5, 3, 6, 4};
- Solution S1;
- int res = S1.maxProfit(test);
- std::cout << res << std::endl;
- return 0;
- }
主要思路:
采用二叉树深度递归搜索,对于每一个结点,其最大路径和可能为以下四种情况:cur + cur->left, cur + cur->right, cur, cur + cur->left + cur->right;
对于每一个结点,其返回给上层的最大路径,可能为以下三种情况:cur + cur->left, cur + cur->right, cur;
- #include
- #include
- #include
-
- 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 maxPathSum(TreeNode* root) {
- dfs(root);
- return max;
- }
-
- int dfs(TreeNode* root){
- if(root == nullptr) return 0;
- int left = dfs(root->left);
- int right = dfs(root->right);
- int cur_sum = std::max(
- std::max(
- std::max(left + root->val, right + root->val),
- left + right + root->val),
- root->val);
- max = std::max(cur_sum, max);
- int ret_sum = std::max(std::max(left + root->val, right + root->val), root->val);
- return ret_sum;
- }
- private:
- int max = INT_MIN;
- };
-
- int main(int argc, char *argv[]) {
- // root = [1, 2, 3]
- TreeNode* Node1 = new TreeNode(1);
- TreeNode* Node2 = new TreeNode(2);
- TreeNode* Node3 = new TreeNode(3);
- Node1->left = Node2;
- Node1->right = Node3;
- Solution S1;
- int res = S1.maxPathSum(Node1);
- std::cout << res << std::endl;
- return 0;
- }
主要思路:
利用 unordered_set 实现元素的去重,遍历数组 nums,只处理连续序列最左边的元素(根据其上一个元素是否在 unordered_set 中存在),循环查询其下一个元素是否存在,存在则序列长度 +1;
- #include
- #include
- #include
-
- class Solution {
- public:
- int longestConsecutive(std::vector<int>& nums) {
- std::unordered_set<int> set;
- for(int & num : nums){ // 利用 unordered_set 去重
- set.insert(num);
- }
-
- int max_len = 0;
- for(int i = 0; i < nums.size(); i++){
- int cur_len = 1;
- int cur_num = nums[i];
- if(set.count(cur_num - 1) == 0){ // 连续子序列左边界元素,不是左边界元素则跳过,确保每一个元素只遍历一次
- while(set.count(cur_num + 1) != 0){ // 利用 unordered_set 实现 O(1) 查询
- cur_len++; // 长度++
- cur_num = cur_num + 1; // 右移
- }
- max_len = std::max(max_len, cur_len); // 更新最大长度
- }
- }
- return max_len;
- }
- };
-
- int main(int argc, char *argv[]) {
- // nums = [100, 4, 200, 1, 3, 2]
- std::vector<int> test = {100, 4, 200, 1, 3, 2};
- Solution S1;
- int res = S1.longestConsecutive(test);
- std::cout << res << std::endl;
- return 0;
- }
主要思路:
按位异或,出现两次的数字会两两对消,最后只剩下出现过一次的数字;
- #include
- #include
-
- class Solution {
- public:
- int singleNumber(std::vector<int>& nums) {
- int res = 0;
- for(int num : nums){
- res = res ^ num; // 按位异或
- }
- return res;
- }
- };
-
- int main(int argc, char *argv[]) {
- // nums = [4, 1, 2, 1, 2]
- std::vector<int> test = {4, 1, 2, 1, 2};
- Solution S1;
- int res = S1.singleNumber(test);
- std::cout << res << std::endl;
- return 0;
- }
主要思路:
基于动态规划,dp[i] 表示字符串 s 前 i 个字符匹配(即可以由字典的字符串构建而成);
初始化 dp[0] = true;
状态转移方程为:dp[i] == dp[j] && s.substr(j, i-j),0 <= j <= i,只要有一个情况匹配即可;
- #include
- #include
- #include
- #include
-
- class Solution {
- public:
- bool wordBreak(std::string s, std::vector
& wordDict) { - std::unordered_set
hash; - for(std::string str : wordDict){
- hash.insert(str);
- }
-
- std::vector<bool> dp(s.length() + 1, 0); // dp[i] 表示前 i 个字符构成的字符串匹配
- // 初始化
- dp[0] = true;
- // 遍历
- for(int i = 1; i <= s.length(); i++){
- for(int j = 0; j <= i; j++){
- if (dp[j] && hash.find(s.substr(j, i - j)) != hash.end()) { // 前 j 个字符匹配,且后 i -j 个字符也匹配
- dp[i] = true;
- break; // 找到一种情况就 break
- }
- }
- }
- return dp[s.length()];
- }
- };
-
- int main(int argc, char *argv[]) {
- // s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
- std::string str = "catsandog";
- std::vector
wordDict = {"cats", "dog", "sand", "and", "cat"}; - Solution S1;
- bool res = S1.wordBreak(str, wordDict);
- if(res) std::cout << "true" << std::endl;
- else std::cout << "false" << std::endl;
- return 0;
- }
主要思路:
经典快慢指针,判断两个指针是否相遇即可;
- #include
-
- struct ListNode {
- int val;
- ListNode *next;
- ListNode(int x) : val(x), next(NULL) {}
- };
-
- class Solution {
- public:
- bool hasCycle(ListNode *head) {
- if(head == nullptr) return false;
- ListNode* slow = head;
- ListNode* fast = head;
- while(fast != nullptr && fast->next != nullptr){
- fast = fast->next->next;
- slow = slow->next;
- if(fast == slow) return true;
- }
- return false;
- }
- };
-
- int main(int argc, char *argv[]) {
- // head = [3,2,0,-4], pos = 1
- ListNode *Node1 = new ListNode(3);
- ListNode *Node2 = new ListNode(2);
- ListNode *Node3 = new ListNode(0);
- ListNode *Node4 = new ListNode(-4);
-
- Node1->next = Node2;
- Node2->next = Node3;
- Node3->next = Node4;
- Node4->next = Node2;
-
- Solution S1;
- int res = S1.hasCycle(Node1);
- if(res) std::cout << "true" << std::endl;
- else std::cout << "false" << std::endl;
- return 0;
- }