Leetcode 数据结构入门(C++) 每题第一个代码均为本人所写代码,并非最优解,部分解法参考题解。
第 1 天 数组 给你一个整数数组 nums
。如果任一值在数组中出现 至少两次 ,返回 true
;如果数组中每个元素互不相同,返回 false
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : bool containsDuplicate (vector<int >& nums) { unordered_map<int ,int > m; bool result=false ; for (int i=0 ;i<nums.size ();i++) { if (m.find (nums[i])==m.end ()) m[nums[i]]=1 ; else if (m[nums[i]]) { result=true ; break ; } } return result; } };
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
class Solution {public : int maxSubArray (vector<int >& nums) { int sum=nums[0 ],result=nums[0 ]; for (int i=1 ;i<nums.size ();i++) { if (sum<0 ) sum=0 ; sum+=nums[i]; if (sum>result) result=sum; } return result; } };
第 2 天 数组 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : vector<int > twoSum (vector<int >& nums, int target) { vector<int > result; unordered_map<int ,int > hash; for (int i=0 ;i<nums.size ();i++) { if (hash.find (target-nums[i])!=hash.end ()) { result.push_back (hash[target-nums[i]]); result.push_back (i); break ; } hash[nums[i]]=i; } return result; } };
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Solution {public : void merge (vector<int >& nums1, int m, vector<int >& nums2, int n) { vector<int > result; int length=m+n; int r1=m,r2=n; for (int i=0 ;i<length;i++) { if (r1>0 &&r2>0 ) { if (nums1[m-r1]<=nums2[n-r2]) { result.push_back (nums1[m-r1]); nums1.pop_back (); r1--; } else { result.push_back (nums2[n-r2]); nums2.pop_back (); r2--; } } else if (r1>0 ) { result.push_back (nums1[m-r1]); nums1.pop_back (); r1--; } else if (r2>0 ) { result.push_back (nums2[n-r2]); nums2.pop_back (); r2--; } } nums1=result; } };
第 3 天 数组 给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution {public : vector<int > intersect (vector<int >& nums1, vector<int >& nums2) { unordered_map<int ,int > hash1; for (int i=0 ;i<nums1.size ();i++) { if (hash1.find (nums1[i])==hash1.end ()) { hash1[nums1[i]]=1 ; } else { hash1[nums1[i]]++; } } vector<int > result; for (int i=0 ;i<nums2.size ();i++) { if (hash1[nums2[i]]>0 ) { hash1[nums2[i]]--; result.push_back (nums2[i]); } } return result; } };
时间复杂度:O(max(nums1.length, nums2.length)) 即O(n)
数组,哈希表,排序
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : int maxProfit (vector<int >& prices) { int result=0 ; int bgn=0x3f3f3f ; for (int i=0 ;i<prices.size ();i++) { if (prices[i]<bgn) { bgn=prices[i]; } if (prices[i]>bgn&&result<prices[i]-bgn) { result=prices[i]-bgn; } } return result; } };
第 4 天 数组 在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。
给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 r 和 c ,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。
如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : vector<vector<int >> matrixReshape (vector<vector<int >>& mat, int r, int c) { int m=mat.size (); int n=mat[0 ].size (); int num=m*n; if (r*c!=num) return mat; vector<vector<int >> result (r,vector <int >(c)); for (int i=0 ;i<r;i++) { for (int j=0 ;j<c;j++) { result[i][j]=mat[(c*i+j)/n][(c*i+j)%n]; } } return result; } };
给定一个非负整数 numRows
, 生成「杨辉三角」的前 numRows
行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution {public : vector<vector<int >> generate (int numRows) { vector<vector<int >> result (numRows); result[0 ]={1 }; for (int i=1 ;i<numRows;i++) { for (int j=0 ;j<i+1 ;j++) { int num=0 ; if (j-1 >=0 ) num+=result[i-1 ][j-1 ]; if (j<=i-1 ) num+=result[i-1 ][j]; result[i].push_back (num); } } return result; } };
第 5 天 数组 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 class Solution {public : bool isValidSudoku (vector<vector<char >>& board) { for (int i=0 ;i<9 ;i++) { unordered_map<char ,int > hash; for (int j=0 ;j<9 ;j++) { if (board[i][j]>='0' &&board[i][j]<='9' ) { if (hash[board[i][j]]==0 ) { hash[board[i][j]]=1 ; } else { return false ; } } else continue ; } } for (int j=0 ;j<9 ;j++) { unordered_map<char ,int > hash; for (int i=0 ;i<9 ;i++) { if (board[i][j]>='0' &&board[i][j]<='9' ) { if (hash[board[i][j]]==0 ) { hash[board[i][j]]=1 ; } else { return false ; } } else continue ; } } for (int k=0 ;k<9 ;k++) { unordered_map<char ,int > hash; for (int i=0 ;i<3 ;i++) { for (int j=0 ;j<3 ;j++) { char num=board[k/3 *3 +i][k%3 *3 +j]; if (num>='0' &&num<='9' ) { if (hash[num]==0 ) { hash[num]=1 ; } else { return false ; } } else continue ; } } } return true ; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class Solution {public : void setZeroes (vector<vector<int >>& matrix) { int m=matrix.size (); int n=matrix[0 ].size (); bool first_row=0 ,first_col=0 ; for (int j=0 ;j<n;j++) { if (matrix[0 ][j]==0 ) { first_row=1 ; break ; } } for (int i=0 ;i<m;i++) { if (matrix[i][0 ]==0 ) { first_col=1 ; break ; } } for (int i=1 ;i<m;i++) { for (int j=1 ;j<n;j++) { if (matrix[i][j]==0 ) { matrix[0 ][j]=0 ; matrix[i][0 ]=0 ; } } } for (int j=1 ;j<n;j++) { if (matrix[0 ][j]==0 ) { for (int i=1 ;i<m;i++) { matrix[i][j]=0 ; } } } for (int i=1 ;i<m;i++) { if (matrix[i][0 ]==0 ) { for (int j=1 ;j<n;j++) { matrix[i][j]=0 ; } } } if (first_row==1 ) { for (int j=0 ;j<n;j++) { matrix[0 ][j]=0 ; } } if (first_col==1 ) { for (int i=0 ;i<m;i++) { matrix[i][0 ]=0 ; } } } };
时间复杂度O(m*n)
空间复杂度O(1)
数组,矩阵
第 6 天 字符串 给定一个字符串 s
,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1
。
class Solution {public : int firstUniqChar (string s) { unordered_map<char ,int > hash; for (int i=0 ;i<s.length ();i++) { hash[s[i]]++; } for (int i=0 ;i<s.length ();i++) { if (hash[s[i]]==1 ) return i; } return -1 ; } };
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : bool canConstruct (string ransomNote, string magazine) { unordered_map<char ,int > hash; for (int i=0 ;i<magazine.length ();i++) { hash[magazine[i]]++; } for (int i=0 ;i<ransomNote.length ();i++) { hash[ransomNote[i]]--; if (hash[ransomNote[i]]<0 ) return false ; } return true ; } };
时间复杂度:O(max(ransomNotr,magazine)) 即O(n)
字符串,哈希表,计数
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : bool isAnagram (string s, string t) { unordered_map<char ,int > hash; for (int i=0 ;i<s.length ();i++) { hash[s[i]]++; } for (int i=0 ;i<t.length ();i++) { hash[t[i]]--; if (hash[t[i]]<0 ) return false ; } for (int i=0 ;i<s.length ();i++) { if (hash[s[i]]>0 ) return false ; } return true ; } };
时间复杂度:O(max(s.length(),t.length())) 即O(n)
字符串,哈希表
第 7 天 链表 给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
1. 标记法(根据题目所给取值) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : bool hasCycle (ListNode *head) { ListNode *now=head; while (now!=NULL &&now->next!=NULL ) { if (now->val==100001 ) { return true ; } now->val=100001 ; now=now->next; } return false ; } };
2. 快慢指针(推荐) 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution {public : ListNode* mergeTwoLists (ListNode* list1, ListNode* list2) { if (list1==NULL ) return list2; if (list2==NULL ) return list1; if (list1->val<list2->val) { list1->next=mergeTwoLists (list1->next,list2); return list1; } else { list2->next=mergeTwoLists (list1,list2->next); return list2; } } };
时间复杂度:O(n+m),其中n、m分别为两链表长度
递归,链表
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution {public : ListNode* removeElements (ListNode* head, int val) { ListNode *H= new ListNode (); H->next=head; ListNode *p=H; while (p!=NULL &&p->next!=NULL ) { if (p->next->val==val) { p->next=p->next->next; } else p=p->next; } return H->next; } };
第 8 天 链表 给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution {public : ListNode* reverseList (ListNode* head) { ListNode* res=NULL ; ListNode* cur=head; while (cur!=NULL ) { ListNode* temp=cur; cur=cur->next; temp->next=res; res=temp; } return res; } };
给定一个已排序的链表的头 head
, 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution {public : ListNode* deleteDuplicates (ListNode* head) { ListNode* cur=head; while (cur!=NULL ) { if (cur->next!=NULL &&cur->next->val==cur->val) { cur->next=cur->next->next; } else { cur=cur->next; } } return head; } };
第 9 天 栈/队列 给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution {public : bool isValid (string s) { stack<char > left; int len=s.length (); for (int i=0 ;i<len;i++) { if (s[i]=='(' ||s[i]=='{' ||s[i]=='[' ) { left.push (s[i]); } else if (left.empty ()) { return false ; } else { char ch=left.top (); left.pop (); if (s[i]==')' &&ch!='(' ) return false ; else if (s[i]=='}' &&ch!='{' ) return false ; else if (s[i]==']' &&ch!='[' ) return false ; } } if (left.size ()) return false ; return true ; } };
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头的元素 boolean empty() 如果队列为空,返回 true ;否则,返回 false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 class MyQueue {public : stack<int > a; stack<int > b; MyQueue () { } void push (int x) { a.push (x); } int pop () { while (!a.empty ()) { b.push (a.top ()); a.pop (); } int ret=b.top (); b.pop (); while (!b.empty ()) { a.push (b.top ()); b.pop (); } return ret; } int peek () { while (!a.empty ()) { b.push (a.top ()); a.pop (); } int ret=b.top (); while (!b.empty ()) { a.push (b.top ()); b.pop (); } return ret; } bool empty () { return a.empty (); } };
第 10 天 树 给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
迭代法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : vector<int > preorderTraversal (TreeNode* root) { vector<int > ret; stack<TreeNode*> data; TreeNode* p=root; while (p!=NULL ) { if (p->right!=NULL ) data.push (p->right); if (p->left!=NULL ) data.push (p->left); ret.push_back (p->val); if (data.empty ()) break ; p=data.top (); data.pop (); } return ret; } };
时间复杂度:O(n),n为节点个数
栈,树,二叉树
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution {public : vector<int > preorderTraversal (TreeNode* root) { vector<int > result; if (!root) return result; stack<TreeNode*> stk; stk.push (root); while (!stk.empty ()) { TreeNode* node = stk.top (); stk.pop (); if (node) { if (node -> right){ stk.push (node -> right); } if (node -> left){ stk.push (node -> left); } stk.push (node); stk.push (nullptr ); } else { result.push_back (stk.top ()->val); stk.pop (); } } return result; } };
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
迭代 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : vector<int > inorderTraversal (TreeNode* root) { vector<int > ret; stack<TreeNode*> data; TreeNode* p=root; while (p!=NULL ||!data.empty ()) { while (p!=NULL ) { data.push (p); p=p->left; } p=data.top (); data.pop (); ret.push_back (p->val); p=p->right; } return ret; } };
时间复杂度:O(n),n为节点个数
栈,树,二叉树
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public: //左 根 右 vector<int> inorderTraversal(TreeNode* root) { vector<int> result; if(!root) return result; stack<TreeNode*> stk; stk.push(root); while(!stk.empty()) { TreeNode* node = stk .top(); stk.pop(); if(node ) { if (node -> right ){ stk.push(node -> right ); } stk.push(node ); stk .push(nullptr); //分隔父节点和子节点,作为输出(入结果栈)标识 if(node -> left ){ stk.push(node -> left ); } } else { result.push_back(stk.top()->val); stk.pop(); } } return result; } };
给你一棵二叉树的根节点 root
,返回其节点值的 后序遍历 。
迭代 模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution {public : vector<int > postorderTraversal (TreeNode* root) { vector<int > result; if (!root) return result; stack<TreeNode*> stk; stk.push (root); while (!stk.empty ()) { TreeNode* node = stk.top (); stk.pop (); if (node) { stk.push (node); stk.push (nullptr ); if (node -> right){ stk.push (node -> right); } if (node -> left){ stk.push (node -> left); } } else { result.push_back (stk.top ()->val); stk.pop (); } } return result; } };
第 11 天 树 给你二叉树的根节点 root
,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Solution {public : vector<vector<int >> levelOrder (TreeNode* root) { queue<TreeNode*> now; now.push (root); TreeNode* p; vector<vector<int >> result; while (!now.empty ()) { queue<TreeNode*> next; vector<int > vec; while (!now.empty ()) { p=now.front (); now.pop (); if (p) { vec.push_back (p->val); if (p->left) next.push (p->left); if (p->right) next.push (p->right); } } if (!vec.empty ()) result.push_back (vec); now=next; } return result; } };
时间复杂度:O(n),n为节点个数
树,广度优先搜索,二叉树
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : int maxDepth (TreeNode* root) { return root==NULL ? 0 : max (maxDepth (root->left),maxDepth (root->right))+1 ; } };
时间复杂度:O(n),n为节点个数
树,深度优先搜索,二叉树
给你一个二叉树的根节点 root
, 检查它是否轴对称。
迭代法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 class Solution {public : bool isSymmetric (TreeNode* root) { queue<TreeNode*> left; queue<TreeNode*> right; if (root->left) left.push (root->left); if (root->right) right.push (root->right); TreeNode* p=root; TreeNode *l,*r; while (!left.empty ()||!right.empty ()) { if (left.size ()!=right.size ()) return false ; l=left.front (); left.pop (); r=right.front (); right.pop (); if (l->val!=r->val) return false ; if (l->left) { left.push (l->left); if (r->right==NULL ) return false ; } if (l->right) { left.push (l->right); if (r->left==NULL ) return false ; } if (r->right) { right.push (r->right); if (l->left==NULL ) return false ; } if (r->left) { right.push (r->left); if (l->right==NULL ) return false ; } } return true ; } };
时间复杂度:O(n),n为节点个数
树,广度优先搜索,二叉树
第 12 天 树 给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
递归法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : TreeNode* invertTree (TreeNode* root) { if (!root) return root; swap (root->left,root->right); root->left=invertTree (root->left); root->right=invertTree (root->right); return root; } };
时间复杂度:O(n),n为节点个数
树,二叉树,深度优先搜索
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 * 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 hasPathSum (TreeNode* root, int targetSum) { if (!root) { return false ; } else if (!root->left&&!root->right) { if (targetSum!=root->val) return false ; else return true ; } else { return hasPathSum (root->left,targetSum-root->val)||hasPathSum (root->right,targetSum-root->val); } } };
第 13 天 树 给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : TreeNode* searchBST (TreeNode* root, int val) { if (root==NULL ) return NULL ; else if (root->val==val) return root; else if (root->val<val) return searchBST (root->right,val); else return searchBST (root->left,val); } };
时间复杂度:O(logN)
树,二叉树,二叉搜索树
给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Solution {public : TreeNode* insertIntoBST (TreeNode* root, int val) { TreeNode *p=root; TreeNode *node=new TreeNode (val); if (root==NULL ) return node; while (p) { if (val<p->val) { if (p->left) p=p->left; else { p->left=node; break ; } } else { if (p->right) p=p->right; else { p->right=node; break ; } } } return root; } };
时间复杂度:O(logN)
树,二叉树,二叉搜索树
遍历法
第 14 天 树 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public : bool isValidBST (TreeNode* root) { long long int lastVal=LONG_MIN; stack<TreeNode*> data; TreeNode* p=root; while (p!=NULL ||!data.empty ()) { while (p!=NULL ) { data.push (p); p=p->left; } p=data.top (); data.pop (); if (p->val<=lastVal) return false ; else lastVal=p->val; p=p->right; } return true ; } };
时间复杂度$O(n)$,n为结点数
树,二叉树,二叉搜索树,深度优先搜索
给定一个二叉搜索树 root
和一个目标结果 k
,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution {public : bool findTarget (TreeNode* root, int k) { vector<int > ret; stack<TreeNode*> data; TreeNode* p=root; while (p!=NULL ||!data.empty ()) { while (p!=NULL ) { data.push (p); p=p->left; } p=data.top (); data.pop (); ret.push_back (p->val); p=p->right; } int l=0 ,r=ret.size ()-1 ; while (l<r) { if (ret[l]+ret[r]==k) return true ; if (ret[l]+ret[r]<k) l++; else r--; } return false ; } };
时间复杂度$O(n)$,n为结点数
树,二叉树,二叉搜索树,深度优先搜索,双指针
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution {public : TreeNode* lowestCommonAncestor (TreeNode* root, TreeNode* p, TreeNode* q) { if (p->val==root->val||q->val==root->val) return root; else if ((p->val<root->val)^(q->val<root->val)) return root; else if (p->val<root->val) return lowestCommonAncestor (root->left,p,q); else return lowestCommonAncestor (root->right,p,q); } };