1.二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
图片说明
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身
思路:利用递归,如果当前结点 root等于NULL,则直接返回NULL;如果 root 等于 p 或者 q ,那这棵树一定返回p 或者q;然后递归左右子树,因为是递归,使用函数后可认为左右子树已经算出结果,用left 和 right表示;此时若left为空,那最终结果只要看 right;若 right 为空,那最终结果只要看 left;如果 left 和 right都非空,因为只给了 p 和 q 两个结点,都非空,说明一边一个,因此 root 是他们的最近公共祖先如果 left 和 right 都为空,则返回空。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr) return nullptr;
        if(root==p||root==q) return root;
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);
        if(left==nullptr) return right;
        if(right==nullptr) return left;//一个为空的话,另一个就是公共祖先
        if(left&&right)
        {
            return root;//都非空的话,此时p,q分别位于最大的左右子树
        }
        return nullptr;       
    }
};

2.字符串的序列
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路:循环里套递归,得到所有排列组合,注意当放入一个字符串时,要判断当前结果数组里有没有这个字符串。

class Solution {
public:
    vector<string> Permutation(string str) {
        vector<string> result;
        if(str.empty()) return result;
        exChange(str,result,0);
        sort(result.begin(),result.end());
        return result;     
    }
    void exChange(string str,vector<string> &result,int begin)
    {
        if(begin==str.size()-1)
        {
            if(find(result.begin(),result.end(),str)==result.end())
            {
                result.push_back(str);//不重复的放进去
            }

        }
        else
        {
          for(int i=begin;i<str.size();i++)
           {
            swap(str[i],str[begin]);
            exChange(str,result,begin+1);//递归排列剩下的序列
            swap(str[i],str[begin]);//换回来再换回去
            }  
        }

    }
    void swap(char &x,char &y)
    {
        char z;
        z=x;
        x=y;
        y=z;
    }
};

3.数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路:从头开始遍历,首先记录第一个数,记出现次数为1,如果下一个数等于它,则次数++,如不等于,则次数--。当次数为0时,开始设置记录下一个数,扔记出现次数为1.最后计算剩下的数字在数组中出现的次数,如大于1/2数组长度,返回这个数;否则,数组内没有出现次数超过一半的数字。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int len=numbers.size();
        if(len==0) return 0;
        int res=numbers[0];
        int count=1;
        for(int i=1;i<len;i++)
        {
            if(numbers[i]==res)
            {
                count++;//相等,次数+1
            }
            else
            {
                count--;//不等,次数-1
            }
            if(count==0)
            {
                res=numbers[i];
                count=1;//重新记录下一个数
            }
        }
        count=0;
        for(int i=0;i<len;i++)
        {
            if(numbers[i]==res)
            {
                count++;//记录最后剩下的数在数组中出现的总次数
            }
        }
        return count*2>len?res:0; 
    }
};

4.最小的K个数
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路:基于快速排序。随机生成一个index,如果这个index等于k-1,说明此数包括前面的数正好是最小的k个数。(因为快排,index前面的数都小于它,后面的数都大于它)。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        int len=input.size();
        if(len<=0||k<=0||k>len) return res;
        int start=0;
        int end=len-1;
        int index=Partition(input,len,start,end);
        while(index!=k-1)
        {
            if(index>k-1)//说明最小的k个数字在前面
            {
                end=index-1;
                index=Partition(input,len,start,end);
            }
            else//说明最小的k个数字在后面
            {
                start=index+1;
                index=Partition(input,len,start,end);
            }
        }//直到index为k时,此时前k个数就是最小的k个数
        for(int i=0;i<k;i++)
            res.push_back(input[i]);
        return res;
    }
    int Partition(vector<int> &numbers,int length,int start,int end)//快排核心函数
    {
        if(length<=0||start<0||end>=length)
            return false;
        int index=RandomInRange(start,end);
        Swap(&numbers[index],&numbers[end]);//随机生成一个点,与尾结点互换
        int small=start-1;
        for(index=start;index<end;index++)
        {
            if(numbers[index]<numbers[end])
            {
                ++small;
                if(small!=index)
                    Swap(&numbers[index],&numbers[small]);//说明small与index之间有大于end下标的数字,把小于数组尾的数放到前面
            }
        }
        ++small;
        Swap(&numbers[small],&numbers[end]);
        return small;//small前面,都小于它,后面都大于它
    }
    int RandomInRange(int start,int end)
   {
         srand (time(NULL));
         return rand() % (end-start+1) + start;//随机数函数
   }
    void Swap(int *a,int *b)
    {
        int temp=*a;
        *a=*b;
        *b=temp;
    }
};

PS:快速排序代码

    void QuickSort(int data[],int length,int start,int end)
    {
        if(start==end)
            return;//终止条件
        int index=Partition(data,length,start,end);
        if(index>start)
        {
            QuickSort(data,length,start,index-1);
        }
        if(index<end)
        {
            QuickSort(data,length,index+1,end);
        }
    }