Bootstrap

C++_Leetcode刷题之路——简单(持续更新)

目录

1. 两数之和

 解一:

 解二: 

 7. 整数反转

解一: 

9. 回文数

解一:

13. 罗马数字转整数

解一: 

14. 最长公共前缀

解一:

20. 有效的括号

解一:

21. 合并两个有序链表

解一:

26. 删除有序数组中的重复项

解一:

27. 移除元素

解一:

28. 实现 strStr()

解一:

35. 搜索插入位置

解一:

53. 最大子序和

解一:

解二:

58. 最后一个单词的长度

解一:

66. 加一

解一:

解二:

67. 二进制求和

解一

解二

69. x 的平方根

解一:

 70. 爬楼梯

解一:

83. 删除排序链表中的重复元素

 解一:

88. 合并两个有序数组

 解一: 

 解二: 

 94. 二叉树的中序遍历

 解一: 

 解二: 

 解三: 

100. 相同的树

 解一: 

101. 对称二叉树

 解一: 

 解二: 

 解三:

104. 二叉树的最大深度

 解一: 

108. 将有序数组转换为二叉搜索树

 解一: 

110. 平衡二叉树

 解一: 

 111. 二叉树的最小深度

 解一: 

 解二: 

 解三: 

112. 路径总和

 解一: 

118. 杨辉三角

 解一: 

119. 杨辉三角 II

 解一: 

121. 买卖股票的最佳时机

 解一: 

122. 买卖股票的最佳时机 II

 解一: 

 解二: 

125. 验证回文串

 解一: 

136. 只出现一次的数字

 解一: 

141. 环形链表

 解一: 

 解二: 

144. 二叉树的前序遍历

 解一: 

 解二: 

 解三: 

145. 二叉树的后序遍历

 解一: 

 解二: 

155. 最小栈

 解一: 

160. 相交链表

 解一: 

 解二: 

167. 两数之和 II - 输入有序数组

 解一: 

68. Excel表列名称

 解一: 

169. 多数元素

 解一: 

 解二: 

171. Excel 表列序号

 解一: 

172. 阶乘后的零

 解一: 


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&&currentindex<=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;
        }
};

;