目录
1. 两数之和
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
解一:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> HashMap;
for (int i = 0; i < nums.size(); i++) {
//1.判断target-nums[i]是是否在hashmap中
//如果有,则说明找到了
//没有则将nums[i]:i键值对放入hashmap中
if (HashMap.count(target- nums[i])) {
//cout << HashMap[target - nums[i]]<< "and" << i<< endl;
return {HashMap[target - nums[i]],i};
break;
}
else {
HashMap[nums[i]] = i;
}
}
return {};
}
};
解二:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int i,j;
for(i=0;i<nums.size();i++){
for(j=i+1;j<nums.size();j++){
if(nums[i]+nums[j]==target)
{
return {i,j};
}
}
}
return {i,j};
}
};
7. 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 2:
输入:x = -123
输出:-32
解一:
class Solution {
public:
int reverse(int x) {
int ans = 0;
while (x != 0) {
if (x > 0 && ans > (pow(2,31)-1 - x % 10) / 10) return 0;
if (x < 0 && ans < (-pow(2,31) - x % 10) / 10) return 0;
// x=123
// x%10=3
// x/10=12
ans = ans * 10 + x % 10;
x /= 10;
}
return ans;
}
};
9. 回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
示例1:
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
解一:
class Solution {
public:
bool isPalindrome(int x) {
int ans = 0;
int y=x;
bool sign;
while (x != 0) {
if (x > 0 && ans > (pow(2,31)-1 - x % 10) / 10) return false;
if (x < 0) return false;//负数一定不是回文数
// x=123
// x%10=3
// x/10=12
ans = ans * 10 + x % 10;
x /= 10;
}
sign=(ans==y);
return sign;
}
};
13. 罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 4:
输入: "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3
解一:
class Solution {
private:
//hashmap,类似于python字典
unordered_map<char, int> hashmap = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
public:
int romanToInt(string s) {
int ans=0;
for( int i=0;i<s.length();i++){
int value=hashmap[s[i]];
int valuenext=hashmap[s[i+1]];
if(i<s.length()-1 && value< valuenext)//罗马数字的规则,左边比右边小,右边减去左边
ans=ans-value;
else//罗马数字的规则,左边比右边大,右边加上左边
ans=ans+value;
}
return ans;
}
};
14. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
解一:
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(!strs.size())
return "";
int length=strs[0].size();//以第一个字符串为标准
int n=strs.size();//看有多少个字符串
cout<<length<<endl;
cout<<n<<endl;
for(int i=0;i<length;++i){
char s1=strs[0][i];//标记第一个字符串当前扫描列的字母
for(int j=1;j<n;j++){//从第二个字符串开始,如果当前列与第一个字符串当前列不相等,那么就结束
if(i==strs[j].size()||strs[j][i]!=s1){
cout<<strs[0].substr(0,i+1)<<endl;
return strs[0].substr(0,i);//输出相同的字母
}
}
}
return strs[0];//只有一个字符串
}
};
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 2:
输入:s = "()[]{}"
输出:true
解一:
class Solution {
public:
bool isValid(string s) {
unordered_map<char,int> map={
{'(',1},
{'{',2},
{'[',3},
{')',4},
{'}',5},
{']',6}
};
stack<char> st;
bool istrue=true;
for(char c:s){
int currentindex=map[c];//当前括号在map中的位置
if(currentindex>=1&¤tindex<=3){//左括号
st.push(c);//入栈
cout<<c<<"入栈"<<endl;
}
//当前的括号是右括号,看最顶端元素是不是和这个括号配对,如果是,就弹出它
else if(!st.empty()&& map[st.top()]==currentindex-3) {
cout<<st.top()<<"出栈"<<endl;
st.pop();
}
else{
istrue=false;
}
}
if(!st.empty()) istrue=false;//不为空,肯定是没有配对成功
return istrue;
}
};
21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
解一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//谁比较长就返回谁
if(l1==NULL)
{
//cout<<"if(l1==NULL) l2->val:"<<l2->val<<endl;
return l2;
}
if(l2==NULL)
{
//cout<<"if(l2==NULL) l1->val:"<<l1->val<<endl;
return l1;
}
//如果l1的值比较小,那么把l2挂在l1的后面,继续拿l1下一个与当前l2作比较
if(l1->val < l2->val){
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}else{
l2->next = mergeTwoLists(l1,l2->next);
return l2;
}
}
};
26. 删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
示例 2:
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
解一:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n=nums.size();
if(n<1)
{
return n;
}
else{
// cout<<n<<endl;
int slow=0;
for(int fast=1;fast<n;fast++)
{
if(nums[fast]!=nums[slow])
{
nums[++slow]=nums[fast];
}
}
return slow+1;
}
}
};
27. 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
解一:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int len=nums.size();
int slow=0;
for(int fast=0;fast<len;fast++)
if(nums[fast]!=val){
nums[slow++]=nums[fast];//修改了前面的元素
}
return slow;//nums[0:slow-1]
}
};
28. 实现 strStr()
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
示例 1:
输入:haystack = "hello", needle = "ll"
输出:2
示例 2:
输入:haystack = "aaaaa", needle = "bba"
输出:-1
示例 3:
输入:haystack = "", needle = ""
输出:0
解一:
class Solution {
public:
int strStr(string haystack, string needle) {
//记录两个字符串的长度
int n = haystack.size(), m = needle.size();
int flag=-1;
if (m==0)
return 0;
if(m>n)
return -1;
//外循环,用于遍历haystack
for (int i = 0; i < n-m+1; i++) {
//先判断一下第一个和最后一个字母是否相同,相同再遍历,否则推出
// cout<<"i="<<i<<endl;
//cout<<"n-m+1="<<n-m+1<<endl;
if(haystack[i]==needle[0]&&haystack[i+m-1]==needle[m-1]){
flag=1;
//内循环,用于遍历needle
for (int j = 0; j < m; j++) {
//从第i个字符开始对应,一旦不相等,设置匹配失败,跳出循环
if (haystack[i + j] != needle[j]) {
flag = 0;
break;
}
}
//cout<<flag<<"iii"<<i<<endl;
//能够完整遍历needle,说明匹配成功
if (flag==1) {
return i;
}
}
}
//没有能够完整遍历的
return -1;
}
};
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4
解一:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int i=0;
for(i=0;i<nums.size();i++){
if(nums[i]==target||nums[i]>target)
return i;
}
return i;
}
};
53. 最大子序和
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
解一:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = -pow(2,31);//为什么要定义一个这么小的数,是因为result要和新的count比较,count的值在int区间
int count = 0;
for (int i = 0; i < nums.size(); i++) {
count += nums[i]; //从第一个数开始求和,
if (count > result) { // 如果求和值比上一次求和结果更大,那么保留这次结果
result = count;
}
if (count <= 0) count = 0; // 如果count小于等于0,那么前面的累计效果对后面没有意义
}
return result;
}
};
解二:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre=0;
int ansMax=nums[0];
int x=0;
//遍历数组的新写法
for (int i=0;i<nums.size();i++) {
//加上这个数和没加前,哪个比较大,
x=nums[i];
cout<<pre<<endl;
pre = max(pre + x, x);//对比当前值和加上之前最大和,哪一个大,作用是f(i)=max(num[0:1])
ansMax=max(ansMax,pre);//对最大和序列在进一步判断最大是多少max(f(0:i))
}
return ansMax;
}
};
58. 最后一个单词的长度
给你一个字符串 s
,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例 2:
输入:s = " fly me to the moon "
输出:4
解一:
class Solution {
public:
int lengthOfLastWord(string s) {
int len=s.size();
int sign=0;
int count=0;
int i=s.size()-1;
while(i>=0&&s[i]==' '){
i--;
}//从后面开始,遍历完所有的空格
while(i>=0){
cout<<s[i]<<endl;
if(s[i]==' ')
break;
i--;
count++;
}
return count;
}
};
66. 加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 2:
输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。
解一:
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int len = digits.size();
for(int i = len - 1; i >= 0; i-- ) {
if(digits[i] == 9) {
digits[i] = 0;
}
else {
digits[i]++;
return digits;
}
}
vector<int> tmp(len + 1,0);
tmp[0] = 1;
return tmp;
}
};
解二:
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
if (digits.size() == 0)
{
return digits;
}
if (digits.size() == 1)
{
if (digits[0] + 1 == 10)
{
digits.push_back(0);
digits[0] = 1;
}
else
{
digits[0] += 1;
}
return digits;
}
for (int i = digits.size()-1; i >=0; i--)
{
if (digits[i] + 1 == 10)
{
if (i == 0)
{
digits.push_back(0);
digits[0] = 1;
}
else
{
digits[i] = 0;
}
}
else
{
digits[i] += 1;
break;
}
}
return digits;
}
};
67. 二进制求和
给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1
和 0
。
示例 2:
输入: a = "1010", b = "1011" 输出: "10101"
解一
class Solution {
public:
string addBinary(string a, string b) {
//字符串是从左到右排列的
string ans;
int n = max(a.size(), b.size()), carry = 0;
int i = a.size()-1;
int j = b.size()-1;
cout<<"i:"<<i<<endl;
cout<<"j:"<<j<<endl;
for (int count=0; count<n; count++) {
//当i<字符串的长度时,进位+a[i]+b[i]
//由于a[i]是字符,true表示1,false代表0
cout<<"i:"<<i<<endl;
cout<<"j:"<<j<<endl;
carry += count < a.size() ? (a[i]=='1') : 0;
carry += count < b.size() ? (b[j]=='1') : 0;
//carry=0,1,2,3
//caryy=0-----0
//caryy=1-----1
//carry=2-----0
//carry=3-----1
ans.push_back((carry % 2) ? '1' : '0');
//carry=2或者3时,进位
carry /= 2;
j--;i--;
}
//如果最后跳出循环了carry=1,说明还需要增加一位
if (carry) {
ans.push_back('1');
}
reverse(ans.begin(), ans.end());
return ans;
}
};
解二
class Solution {
public:
string addBinary(string a, string b) {
//字符串是从左到右排列的
string ans;
//对序列进行反向排列使得低位在左边
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int n = max(a.size(), b.size()), carry = 0;
for (int i = 0; i < n; ++i) {
carry += i < a.size() ? (a.at(i) == '1') : 0;
carry += i < b.size() ? (b.at(i) == '1') : 0;
ans.push_back((carry % 2) ? '1' : '0');
carry /= 2;
}
if (carry) {
ans.push_back('1');
}
reverse(ans.begin(), ans.end());
return ans;
}
};
69. x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 2:
输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
解一:
class Solution {
public:
int mySqrt(int x) {
int l = 0, r = x, ans = -1;
while (l <= r) {
//区间中点
int mid = l + (r - l) / 2;
//如果中点的平方太小,那么从中点的右边在取中点
if ((long long)mid * mid <= x) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
};
class Solution {
public:
int mySqrt(int x) {
if (x == 0) {
return 0;
}
//牛顿迭代法
double C = x, x0 = x;
while (true) {
//迭代格式
double xi = 0.5 * (x0 + C / x0);
//迭代条件
if (fabs(x0 - xi) < 1e-7) {
break;
}
x0 = xi;
}
return int(x0);
}
};
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
解一:
class Solution {
public:
int climbStairs(int n) {
int f0=0,f1=0,f2=1;
for(int i=1;i<=n;i++){
f0=f1;
f1=f2;
f2=f0+f1;
}
return f2;
}
};
83. 删除排序链表中的重复元素
存在一个按升序排列的链表,给你这个链表的头节点 head
,请你删除所有重复的元素,使每个元素 只出现一次 。
返回同样按升序排列的结果链表。
例 2:
输入:head = [1,1,2,3,3]
输出:[1,2,3]
解一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head){
return head;
}
ListNode *current=head;
while(current->next){
if(current->val==current->next->val)
{
current->next=current->next->next;
}
else{
current=current->next;
}
}
return head;
}
};
88. 合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
解一:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int sort[m+n];
int p1=0,p2=0;
int i=0;
while(p1<m||p2<n){
if(p1==m)
sort[i++]=nums2[p2++];
else if(p2==n)
sort[i++]=nums1[p1++];
else if(nums1[p1]>nums2[p2])
sort[i++]=nums2[p2++];
else
sort[i++]=nums1[p1++];
}
for(int i=0;i<m+n;i++){
nums1[i]=sort[i];
}
}
};
解二:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
for(int i=0;i<n;i++){
nums1[m+i]=nums2[i];
}
sort(nums1.begin(), nums1.end());
}
};
94. 二叉树的中序遍历
给定一个二叉树的根节点 root
,返回它的 中序 遍历。
示例 1:
输入:root = [1,null,2,3] 输出:[1,3,2]
解一:
/**
* 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:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
TreeNode *predecessor = nullptr;
while (root != nullptr) {
if (root->left != nullptr) {
// predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
predecessor = root->left;
while (predecessor->right != nullptr && predecessor->right != root) {
predecessor = predecessor->right;
}
// 让 predecessor 的右指针指向 root,继续遍历左子树
if (predecessor->right == nullptr) {
predecessor->right = root;
root = root->left;
}
// 说明左子树已经访问完了,我们需要断开链接
else {
res.push_back(root->val);
predecessor->right = nullptr;
root = root->right;
}
}
// 如果没有左孩子,则直接访问右孩子
else {
res.push_back(root->val);
root = root->right;
}
}
return res;
}
};
解二:
/**
* 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:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;//可变数组
stack<TreeNode*> sta;//建立一个栈,里面存放的是元素的地址
while(root!=nullptr||!sta.empty()){
while(root!=nullptr){
sta.push(root);//左边的节点依次压入栈
root=root->left;
}//root指向null
root=sta.top();//指向最后一个左子孙
sta.pop();
res.push_back(root->val);
root=root->right;
}
return res;
}
};
解三:
/**
* 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:
void inorder(TreeNode* root,vector<int> &res)
{
if(!root)
return ;
inorder(root->left,res);
//遍历到最后一个左边,把该元素压入res
res.push_back(root->val);
inorder(root->right,res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;//可变数组
inorder(root,res);
return res;
}
}
100. 相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 3:
输入:p = [1,2,1], q = [1,1,2]
输出:false
解一:
/**
* 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 isSameTree(TreeNode* p, TreeNode* q) {
if(p==nullptr&q==nullptr)
return true;
else if(p==nullptr||q==nullptr)
return false;
else if(p->val!=q->val)
return false;
else {
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
}
};
101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
解一:
/**
* 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 isSymmetric(TreeNode* root) {
return check(root,root);
}
bool check(TreeNode *p, TreeNode *q) {
queue<TreeNode *> u;//建立一个空队列
u.push(p);u.push(q);
while(!u.empty()){
q=u.front();u.pop();
p=u.front();u.pop();
//两个都不为空
if(!p&&!q) continue;
if((!p||!q)||(p->val!=q->val)) return false;
u.push(q->left);
u.push(p->right);
u.push(q->right);
u.push(p->left);
}
return true;
}
};
解二:
/**
* 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 isSymmetric(TreeNode* root) {
if(root==nullptr)
return true;
//调用递归函数,比较左节点,右节点
return isSym(root->left,root->right);
}
bool isSym(TreeNode* right,TreeNode* left){
//递归的终止条件是两个节点都为空
//或者两个节点中有一个为空
//或者两个节点的值不相等
if(right==nullptr&&left==nullptr)
return true;
else if(right==nullptr||left==nullptr)
return false;
else if(right->val!=left->val)
return false;
//再递归的比较 左节点的左孩子 和 右节点的右孩子
//以及比较 左节点的右孩子 和 右节点的左孩子
return isSym(right->right,left->left)&&isSym(left->right,right->left);
}
};
解三:
/**
* 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 isSymmetric(TreeNode* root) {
return check(root,root);
}
bool check(TreeNode *p, TreeNode *q) {
if (!p && !q) return true;
if (!p || !q) return false;
return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
}
};
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
解一:
/**
* 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 maxDepth(TreeNode* root) {
if(root==nullptr)
return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
108. 将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
解一:
/**
* 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:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return helper(nums, 0, nums.size() - 1);
}
TreeNode* helper(vector<int>& nums, int left, int right) {
if (left > right) {
return nullptr;
}
// 总是选择任意一个中间位置的数字作为根节点
int mid = (left + right+ rand() % 2) / 2;
//root=0,left=
TreeNode* root = new TreeNode(nums[mid]);
root->left = helper(nums, left, mid - 1);
root->right = helper(nums, mid + 1, right);
return root;
}
};
110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例 2:
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
解一:
/**
* 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 isBalanced(TreeNode* root) {
if(root==nullptr)
return true;
int sign=abs(height(root->left)-height(root->right));
cout<<sign<<endl;
//保证每个节点的左右节点高度相差不大于1
return (sign<=1)&&isBalanced(root->left)&&isBalanced(root->right);
}
int height(TreeNode* root){
if (root == NULL) {
return 0;
}
else{
return max(height(root->left),height(root->right))+1;
}
}
};
111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
解一:
/**
* 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 minDepth(TreeNode* root) {
if(root==nullptr)
return 0;
//1.左孩子和有孩子都为空的情况,说明到达了叶子节点,直接返回1即可
if(root->left == nullptr && root->right == nullptr) return 1;
//2.如果左孩子和由孩子其中一个为空,那么需要返回比较大的那个孩子的深度
int m1 = minDepth(root->left);
int m2 = minDepth(root->right);
//这里其中一个节点为空,说明m1和m2有一个必然为0,所以可以返回m1 + m2 + 1;
if(root->left == nullptr || root->right == nullptr) return m1 + m2 + 1;
//3.最后一种情况,也就是左右孩子都不为空,返回最小深度+1即可
return min(m1,m2) + 1;
}
};
解二:
/**
* 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 minDepth(TreeNode* root) {
if(root==nullptr)
return 0;
if (root->left == nullptr && root->right == nullptr) {
return 1;
}
int min_depth = INT_MAX;
//如果左子树不为空,那么比较一下左子树的深
if (root->left != nullptr) {
min_depth = min(minDepth(root->left), min_depth);
}
if (root->right != nullptr) {
min_depth = min(minDepth(root->right), min_depth);
}
//只有满足两边都不为空的时候,最小深度才+1。
return min_depth + 1;
}
};
解三:
/**
* 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 minDepth(TreeNode* root) {
if(root==nullptr)
return 0;
queue<pair<TreeNode *, int> > que;
que.emplace(root, 1);
while (!que.empty()) {
TreeNode *node = que.front().first;
int depth = que.front().second;
que.pop();
if (node->left == nullptr && node->right == nullptr) {
return depth;
}
if (node->left != nullptr) {
que.emplace(node->left, depth + 1);
}
if (node->right != nullptr) {
que.emplace(node->right, depth + 1);
}
}
return 0;
}
};
112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解一:
/**
* 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==nullptr)
return false;
//左右节点都为空
if(root->left==nullptr&&root->right==nullptr){
return targetSum==root->val;
}
cout<<"val:"<<root->val<<endl;
cout<<"targetSum:"<<targetSum<<endl;
return hasPathSum(root->left,targetSum-root->val)||hasPathSum(root->right,targetSum-root->val);
}
};
118. 杨辉三角
给定一个非负整数 numRows
,生成「杨辉三角」的前 numRows
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
解一:
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ret(numRows);
for(int i=0;i<numRows;i++){
ret[i].resize(i+1);//第i行有i+1个元素
ret[i][0]=ret[i][i]=1;//每行第一个元素和最后一个元素都是1;
for(int j=1;j<i;j++){
//i=2,第三行j=1,第二个元素
ret[i][j]=ret[i-1][j-1]+ret[i-1][j];
}
}
return ret;
}
};
119. 杨辉三角 II
给定一个非负索引 rowIndex
,返回「杨辉三角」的第 rowIndex
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: rowIndex = 3
输出: [1,3,3,1]
解一:
class Solution {
public:
vector<int> getRow(int rowIndex) {
//先生成一个杨辉三角
vector<int> ret(rowIndex+1,1);
if(rowIndex < 2) return ret;
for(int i=1;i<rowIndex;++i){
for(int j=i;j>0;--j){
//i=2,第三行j=1,第二个元素
ret[j]=ret[j-1]+ret[j];
}
}
return ret;
}
};
121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
解一:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int inf = 1e9;
int minprice = inf, maxprofit = 0;
for (int price: prices) {
maxprofit = max(maxprofit, price - minprice);
minprice = min(price, minprice);
}
return maxprofit;
}
};
122. 买卖股票的最佳时机 II
给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
解一:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if(n<2){
return 0;
}
int dp[n][2];
// 0:持有现金
// 1:持有股票,
dp[0][0]=0;
//如果持有股票,当前拥有的现金数是当天股价的相反数,即 dp[0][1] = -prices[i]
dp[0][1]=-prices[0];
for(int i=1;i<n;i++){
//今天持有的现金,目前手里有多少钱
//对比今天卖掉股票后的钱和昨天的现金那个比较多
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
//今天持有股票,目前手里有多少钱
//对比今天买入,股票后的现金
//7 2 5
//dp[0][0]=0;dp[0][1]=-7;
//dp[1][0]=0;dp[1][1]=-2;
//dp[2][0]=3;dp[2][1]=-2;
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
}
return dp[n-1][0];
}
};
解二:
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size()<2){
return 0;
}
int profits=0;
for(int i=1;i<prices.size();i++){
//后一个数大于前一个数,那么就保留
profits=profits+max(0,prices[i]-prices[i-1]);
}
return profits;
}
};
125. 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串
解一:
class Solution {
public:
bool isPalindrome(string s) {
string ispa;
for(char ch:s){
if(isalnum(ch)){
ispa += tolower(ch);
}
}
int i=0;int j=ispa.size()-1;
while(i<j){
if(ispa[i]!=ispa[j])
return false;
i++;j--;
}
return true;
}
};
136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 2:
输入: [4,1,2,1,2]
输出: 4
解一:
class Solution {
public:
int singleNumber(vector<int>& nums) {
//任何数与0异或运算是本身
//任何数字与本身异或是0,由于数组中只有一个元素出现一次,将所有元素异或后,成对的元素异或为0,留下的就是出现一次的元素
int ret=0;
for(int i:nums)
ret^=i;
return ret;
}
};
141. 环形链表
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
解一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast=head;
ListNode *slow=head;
//有null肯定是没环
while(fast!=NULL&&fast->next!=NULL){
slow=slow->next;//慢指针走一步,快指针走两步,如果有环的话,肯定会相遇
//fast->next!=NULL是为了保证这一行可以执行
fast=fast->next->next;
if(slow==fast){
return true;
}
}
return false;
}
};
解二:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
unordered_set<ListNode*> map;
while(head!=NULL)
{
if(map.count(head)){//计算hash表中有几个这样的地址
return true;
}
map.insert(head);//把地址插入哈希表
head=head->next;
}
return false;
}
};
144. 二叉树的前序遍历
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
解一:
/**
* 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:
void preorder(TreeNode *root, vector<int> &res) {
if(root==nullptr){
return ;
}
res.push_back(root->val);//放入根节点
preorder(root->left,res);//放入左子树
preorder(root->right,res);//放入右子树
}
vector<int> preorderTraversal(TreeNode* root) {
//前序遍历就是,根节点,左子树,右子树
vector<int> res;
if(root==nullptr){
return res;
}
preorder(root, res);
return res;
}
};
解二:
/**
* 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:
vector<int> preorderTraversal(TreeNode* root) {
//前序遍历就是,根节点,左子树,右子树
vector<int> res;
if(root==nullptr){
return res;
}
//新建一个栈,用来存各个节点的地址
stack <TreeNode*> stk;
//循环终止条件,栈为空且,节点指向null
while(!stk.empty()||root!=nullptr){
while(root!=nullptr){
//把根节点依次压入栈
res.push_back(root->val);
stk.push(root);
root=root->left;
}
root=stk.top();//第一个读出来的是最左子树
stk.pop();//元素取出后,弹出
root=root->right;//然后去寻找她的右节点
}
return res;
}
}
解三:
/**
* 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:
vector<int> preorderTraversal(TreeNode* root) {
//前序遍历就是,根节点,左子树,右子树
vector<int> res;
if(root==nullptr){
return res;
}
TreeNode *p1=root,*p2=nullptr;
while(p1!=nullptr){
p2=p1->left;
if(p2!=nullptr){//如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点:
//p2的右节点不为空,且不等与父节点
while(p2->right!=nullptr&&p2->right!=p1){
p2=p2->right;
}
if(p2->right==nullptr){//如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点。
//然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。
res.push_back(p1->val);
p2->right=p1;
p1=p1->left;
continue;
}else{// 如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。当前节点更新为当前节点的右子节点。
p2->right=nullptr;
}
}else{//如果当前节点的左子节点为空,将当前节点加入答案
res.push_back(p1->val);
}
p1 = p1->right;//往左节点
}
return res;
}
};
145. 二叉树的后序遍历
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
解一:
/**
* 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:
//后序遍历,左右中
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(root==nullptr)
return res;
stack<TreeNode *> stk;
TreeNode *prev = nullptr;
//循环终止条件,栈空,指针也为空
while(!stk.empty()||root!=nullptr){
while(root!=nullptr){
stk.push(root);
root=root->left;
}
//指向最左边的元素
root=stk.top();
stk.pop();
if (root->right == nullptr || root->right == prev) {
res.push_back(root->val);
prev = root;
root = nullptr;
} else {//右边不为空,那么继续往右边遍历
stk.push(root);
root = root->right;
}
}
return res;
}
};
解二:
/**
* 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:
void postorder(TreeNode* root,vector<int> &res){
if(root==nullptr)
return ;
//后序遍历,左右中
postorder(root->left,res);
postorder(root->right,res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(root==nullptr)
return res;
postorder(root,res);
return res;
}
};
155. 最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
示例:
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]输出:
[null,null,null,null,-3,null,0,-2]解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
解一:
class MinStack {
stack<int> x_stack;
stack<int> min_stack;
public:
/** initialize your data structure here. */
MinStack() {
min_stack.push(INT_MAX);
}
void push(int val) {
x_stack.push(val);
min_stack.push(min(min_stack.top(),val));
}
void pop() {
x_stack.pop();
min_stack.pop();
}
int top() {
return x_stack.top();
}
int getMin() {
return min_stack.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
160. 相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
解一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == nullptr || headB == nullptr) {
return nullptr;
}
ListNode *you = headA, *she = headB;
while (you != she) { // 若是有缘,你们早晚会相遇
you = you ? you->next : headB; // 当你走到终点时,开始走她走过的路
she = she ? she->next : headA; // 当她走到终点时,开始走你走过的路
}
return you;
}
};
解二:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode *> map;
while(headA!=nullptr){
map.insert(headA);
headA=headA->next;
}
while(headB!=nullptr){
if(map.count(headB)){
return headB;
}
headB=headB->next;
}
return nullptr;
}
};
167. 两数之和 II - 输入有序数组
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
解一:
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int low = 0, high = numbers.size() - 1;
while (low < high) {
int sum = numbers[low] + numbers[high];
if (sum == target) {
return {low + 1, high + 1};
} else if (sum < target) {
++low;
} else {
--high;
}
}
return {-1, -1};
};
68. Excel表列名称
给你一个整数 columnNumber
,返回它在 Excel 表中相对应的列名称。
解一:
class Solution {
public:
string convertToTitle(int columnNumber) {
string row;
while (columnNumber)
{
//columnNumber=28
//remainder=2
int remainder = columnNumber % 26;
if(remainder==0)//如果余数是0,就像上一位借个1(26)出来,让余数强行等于26
{
remainder = 26;
columnNumber -= 26;
}
//B
row.push_back(remainder+ 64);
//columnNumber=1——————A
columnNumber /= 26;
}
//BA
reverse(row.begin(), row.end());
//A
return row;
}
};
169. 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
解一:
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int> map;
int majority = 0, cnt = 0;
for (int num: nums) {
++map[num];//同样的数字出现一次,键值加一次
if (map[num] > nums.size()/2) {
return num;
cout<<"num:"<<num<<endl;
cout<<"cnt:"<<cnt<<endl;
}
}
return 0;
}
};
解二:
class Solution {
public:
int majorityElement(vector<int>& nums) {
//对数组进行排序,那么大于n/2的元素一定出现在n/2
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};
171. Excel 表列序号
给你一个字符串 columnTitle
,表示 Excel 表格中的列名称。返回该列名称对应的列序号。
解一:
class Solution {
public:
int titleToNumber(string columnTitle) {
int ans=0;
//先反转一下
reverse(columnTitle.begin(),columnTitle.end());
int ex=0;
for(char ch:columnTitle){
ans+=(ch-64)*pow(26,ex);
ex++;
cout<<ch<<endl;
}
return ans;
}
};
172. 阶乘后的零
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
解一:
class Solution {
public:
int trailingZeroes(int n) {
int zero_count=0;
for(int i=1;i<=n;i++){
int N=i;
while(N>1){
if(N%5==0){
zero_count++;
N=N/5;
}else{
break;
}
}
}
return zero_count;
}
};