2

https://github.com/CyC2018/CS...

10-1 斐波那契数列

clipboard.png

int Fibonacci(int n){
    int a1,a2;
    int t;
    a1 = a2 =1;
    if(n == 0){
        return 0;
    }
    if(n == 1|| n==2){
        return 1;
    }
    for(int i=3;i <= n;i++){
        t = a1;
        a1 += a2;
        a2 = t;
    }
    return a1;
}

10-2 矩形覆盖

clipboard.png

int rectCover(int number) {
    int a1,a2;
    int t;
    a1 = 2;
    a2 = 1;
    if(number == 0){
        return 0;
    }
    if(number == 1){
        return 1;
    }else if(number == 2){
        return 2;
    }
    for(int i=3;i <= number;i++){
        t = a1;
        a1 += a2;
        a2 = t;
    }
    return a1;
}

10-3 跳台阶

int jumpFloor(int number) {
    int a1,a2;
    int t;
    a1 = 2;
    a2 = 1;
    if(number == 0){
        return 0;
    }
    if(number == 1){
        return 1;
    }else if(number == 2){
        return 2;
    }
    for(int i=3;i <= number;i++){
        t = a1;
        a1 += a2;
        a2 = t;
    }
    return a1;
}

10-4 变态跳台阶

clipboard.png

int jumpFloorII(int number) {
    int a1,a2;
    int t;
    a1 = 1;
    if(number == 0){
        return 0;
    }
    if(number == 1){
        return 1;
    }
    for(int i=2;i <= number;i++){
        a1 = a1*2;
    }
    return a1;
}

11 旋转数组的最小数字*

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
clipboard.png

int minNumberInRotateArray(vector<int> rotateArray) {
    int st,end,mid;
    end = rotateArray.size()-1;
    st = 0;
    mid = (st+end)/2;
    while(st < end-1){
        if(rotateArray[st] <= rotateArray[mid]){
            st = mid;
        }else{
            end = mid;
        }
        mid = (st+end)/2;
    }
    return rotateArray[st] > rotateArray[end]?rotateArray[end]:rotateArray[st];
}

12 矩阵中的路径*

判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向上下左右移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。

例如下面的矩阵包含了一条 bfce 路径

clipboard.png

使用回溯法

    int x[4]{1,0,-1,0};
    int y[4]{0,1,0,-1};
    int map[10000]={0};
    bool find(char* matrix,int pos,int rows,int cols,char* str,int strpos){
        if(strlen(str) == strpos){
            return true;
        }
        for(int i=0; i<4;i++){
            if(x[i] + pos/cols  < 0
            || x[i] + pos/cols >= rows
            || y[i]+pos%cols >= cols
            || y[i]+pos%cols < 0){
                continue;
            }
            if (map[pos+cols*x[i]+y[i]] == 0
            && matrix[pos+cols*x[i]+y[i]] == str[strpos]){
                map[pos+cols*x[i]+y[i]] = 1;
                if( find(matrix,pos+cols*x[i]+y[i],rows,cols,str,strpos+1)){
                    return true;
                }
                map[pos+cols*x[i]+y[i]] = 0;
            }
        }
        return false;
    }

    bool hasPath(char* matrix, int rows, int cols, char* str)
    {

        for(int i = 0;i < rows;i++){
            for(int j =0;j < cols;j++){
                if (matrix[i*cols+j] == str[0]){
                    map[i*cols+j] = 1;
                    if(find(matrix,i*cols+j,rows,cols,str,1)){
                        return true;
                    }
                    map[i*cols+j] = 0;
                }
            }
        }
        return false;
    }

13 机器人运动范围*

BFS,宽度优先搜索

int map[1000][1000]={0};
int x[4]{1,0,-1,0};
int y[4]{0,1,0,-1};
stack<pair<int,int>> st;
bool IsCanIn(pair<int,int> pos, int threshold){
    int temp;
    int res = 0;
    temp = pos.first;
    while(temp){
        res = res+temp%10;
        temp /= 10;
    }
    temp = pos.second;
    while(temp){
        res = res+temp%10;
        temp /= 10;
    }
    return threshold >= res ? true:false;
}

int movingCount(int threshold, int rows, int cols)
{
    pair<int,int> pos;
    int i;
    int res = 0;
    res ++;
    if(threshold < 0){
        return 0;
    }
    st.push(make_pair(0,0));
    map[0][0] = 1;
    while(!st.empty()){
        pos = st.top();
        st.pop();
//        cout << pos.first << "," << pos.second << endl;
        for(i = 0;i < 4;i++){
            if(pos.first + x[i] >= rows ||
                    pos.first + x[i] < 0 ||
                    pos.second + y[i] >= cols ||
                    pos.second + y[i] < 0){
                continue;
            }

            if(map[pos.first + x[i]][pos.second + y[i]] == 0&&
            IsCanIn(make_pair(pos.first + x[i],pos.second + y[i]),threshold)){//如果还没访问过,且符合要求
                map[pos.first + x[i]][pos.second + y[i]] = 1;
                st.push(make_pair(pos.first + x[i], pos.second + y[i]));//入栈
                res++;
            }
        }
    }

    return res;
}

14 剪绳子**

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。

示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
  1. 当 n=1,这是不可能的。
  2. 当 n=2,分为1,1,结果:1;
  3. 当 n=3,分为1,2,结果:2;
  4. 当 n=4,分为2,2,结果:4;
  5. 当 n>=5 时,我们可以证明 2(n-2)>n 并且 3(n-3)>n。当n>=5的时候,2(n-2) > 3(n-3).

从以上可以知道,我们只需要尽可能的分配更多的3的绳子。还有一点就是为什么是2和3,我不能是4,5,6....这样分,这样分你怎么保证不会比分成3或2小呢。
注意,假如分成4,5,6...,我们可以继续将其分成2或3.更具第5条可以知道,会比n更大,也就是说n=5,分成2,3. 2*3 >5;所以和不一开始就将其分成2,3呢。

贪心算法

int integerBreak(int n) {
    int res = 1;
    int temp = n;
    if(n == 2){
        return 1;
    }else if(n == 3){
        return 2;
    }else if(n == 4){
        return 4;
    }
    while(temp > 4){
        temp -= 3;
        res *= 3;
    }
    if(temp == 2){
        return res * 2;
    }else if(temp == 3){
        return res * 3;
    }else if(temp == 4){
        return res * 4;
    }
}

https://rongxuanhong.github.i...
DP动态规划
如果所求问题是求最优解,而且问题能够分解为若干个子问题,并且子问题之间还有重叠的更小的子问题,那么应该考虑应用动态规划思想求解。
在应用动态规划之前要分析能否把大问题分解成小问题,分解的每个小问题也存在最优解。如果把小问题的最优解组合起来能够得到这个问题的最优解,那么我们就可以应用动态规划解决这个问题。

总之,动态规划存在以下几个特点:

  1. 目标问题是求最优解;
  2. 整体的最优解可以由子问题的最优解参与或组合得到;
  3. 大问题可以分成若干个子问题,且子问题之间还有相互重叠的更小的子问题;
  4. 为避免重复求解子问题(后面求大问题的时候可能多次用到),采用自下而上的顺序先计算小问题的最优解并记录到一维或二维数组中,再根据已经解出的小问题来求出大问题的最优解。简而言之,就是自上而下分析问题,自下而上求解问题。

首先定义函数 f(n) 为把长度为 n 的绳子剪成若干段后的最大乘积值。
剪绳子求的是最大乘积值满足特点 1;
如果在绳子的 i 处剪一刀,那么 f(n) 要达到乘积最大,则 f(i)与 f(n-i) 也要达到乘积最大,满足特点 2;
假设 n=6,那么 f(2) 和 f(4) 都是问题的子问题,但其实 f(2) 也是 f(4) 的子问题,那么就出现了重叠的更小的子问题,满足特点 3;所以,我们为了求解目标问题,都是先从小问题开始求解,即自下而上求解,并将每个子问题的乘积最大值记录到数组中备查,满足特点4。
因此,本题的确适合采用动态规划求解。

当绳子长度为 2 的时候,只能剪成两段长度为 1,所以 f(2)=1;当绳子长度为 3 的时候,有两种剪法,其中最大的 f(3)=2。

那么当 n>4 的时候,我们要求出把长度为 i 的绳子剪成若干段之后各段长度乘积的最大值,即求 f(i),而4<=i<=n,即要求出所有子问题的最优解。那么对于每个子问题 f(i),由于可以有 i/2 种切法,所以我们应该遍历每种切法,并计算出乘积最大的那种切法。当切点在 j(1<=j<=i/2) 处时,子问题 f(i)=max(f(j)xf(i-j)),其中 f(j),f(i-j),都可以从备忘数组中查询得到。

int integerBreak(int n) {
//    1显然不成立
//    在分配中也不能分配1,没意义.
    int* dp = new int[n+1]{0};
    if (n == 2){
        return 1;
    }else if(n == 3){
        return 2;
    }


//    如果可以不剪,其最大就是本身.
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = 3;
    for(int i = 4;i <= n;i++){
        for(int j = 1;j <= i/2;j++){
            dp[i] = max(dp[i],dp[i-j]*dp[j]);
        }
    }
    return dp[n];
}

15 二进制中1的个数

输入一个整数,输出该数二进制表示中 1 的个数。

int  NumberOf1(int n) {
    int res = 0;
    int flag = 1;
    while(flag){
        if(n & flag){
            res++;
        }
        flag <<=1;
    }
    return res;
}

16 数值的整数次方

给定一个 double 类型的浮点数 base 和 int 类型的整数 exponent,求 base 的 exponent 次方。
注意exponent为负


double Power(double base, int exponent) {
    double res = 1;
    if (exponent < 0){
        exponent = -exponent;
        base = 1/base;
    }
    while(exponent){
        if(exponent&1 == 1){
            res = res * base;
        }
        base = base * base;
        exponent/=2;
    }
    return res;
}

17 打印从 1 到最大的 n 位数

void print(int n,string pre){
    if(n == 0){
        if(pre == "0"){
            return;
        }
        cout << pre << " ";
        return;
    }
    for(int i =0;i <=9;i++){

        if(pre == "" && i == 0&&n!=1) {
            print(n - 1, pre);
        }else {
            print(n - 1, pre + char('0' + i));
        }
    }
}

18.2 删除链表中重复的结点**

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};

ListNode* deleteDuplication(ListNode* pHead)
{
    map<int,ListNode*> m1;
    ListNode myHead(0);
    ListNode* t,*pre;
    t = pHead;
//使头节点一般化
    myHead.next = pHead;
    pre = &myHead;
    while(t!=NULL){
        if(m1.find(t->val) == m1.end()){
//            如果还没出现过
            m1[t->val] = pre;
            pre = t;
            t = t->next;
        }else{
            m1[t->val]->next = t->next;
//            下一个节点的前继改为第一次出现该数时的前继
            pre = m1[t->val];
            t = t->next;
        }

    }
    return myHead.next;
}

int main(){
    ListNode ln1{1};
    ListNode ln2{2};
    ListNode ln3{3};
    ListNode ln4{3};
    ListNode ln5{4};
    ListNode ln6{4};
    ln1.next = &ln2;
    ln2.next = &ln3;
    ln3.next = &ln4;
    ln4.next = &ln5;
    ln5.next = &ln6;
    deleteDuplication(&ln1);
    ListNode* head = &ln1;
    while(head != NULL){

        cout << head->val;
        head = head->next;
    }

    return 0;
}

19 正则表达式匹配**

请实现一个函数用来匹配包括 '.' 和 '' 的正则表达式。模式中的字符 '.' 表示任意一个字符,而 '' 表示它前面的字符可以出现任意次(包含 0 次)。

在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串 "aaa" 与模式 "a.a" 和 "abaca" 匹配,但是与 "aa.a" 和 "ab*a" 均不匹配。

bool match(char* str, char* pattern)
{
    if (*str == '\0' && *pattern == '\0')
        return true;
    if (*str != '\0' && *pattern == '\0')
        return false;
    //if the next character in pattern is not '*'
    if (*(pattern+1) != '*')
    {
        if (*str == *pattern || (*str != '\0' && *pattern == '.'))
            return match(str+1, pattern+1);
        else
            return false;
    }
    //if the next character is '*'
    else
    {
        if (*str == *pattern || (*str != '\0' && *pattern == '.'))
            return match(str, pattern+2) || match(str+1, pattern);
        else
            return match(str, pattern+2);
    }
}

20 表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

map<char,bool> m1;
void makemap(){
    m1['e'] = true;
    m1['E'] = true;
    m1['0'] = true;
    m1['1'] = true;
    m1['2'] = true;
    m1['3'] = true;
    m1['4'] = true;
    m1['5'] = true;
    m1['6'] = true;
    m1['7'] = true;
    m1['8'] = true;
    m1['9'] = true;
    m1['+'] = true;
    m1['-'] = true;
    m1['.'] = true;

}
// e,E之后不能有. ---- flag1
// .之后的情况下不能有 .-----flag2
// +/-之后在E出现前不能有+/------flag3
bool isNumeric(char* string)
{
    makemap();
    bool flag1,flag2,flag3;
    int strpos = 0;
    char nowchar;
    flag1 = flag2 = flag3 = false;
    while(strpos < strlen(string)){
        nowchar = string[strpos++];
        if(m1[nowchar]){
            //如果是+/-
            if(nowchar == '+' || nowchar == '-'){
                cout << 1 << endl;
                if(flag3 == true) return false;
                flag3 = true;
            }else if(nowchar == '.'){
                cout << 2 << endl;
                if(flag2 == true || flag1 == true) return false;
                flag2 = true;
            }else if(nowchar == 'e' || nowchar == 'E'){
                cout << 3 << endl;
                if(flag1 == true) return false;
                flag1 = true;
                flag3 = false;
            }else{
                cout << 4 << endl;
                // 避免中途输出+,-
                flag3 = true;
                continue;
            }


        }else{
//            出现a等字符一律死.
            return false;
        }
    }
    if(string[strpos-1] == 'e'||string[strpos-1] == 'E'){
        return false;
    }
    return true;
}

21 调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

void reOrderArray(vector<int> &array) {
    vector<int>::iterator it;
    vector<int> temp;
    int oddCount = 0;
    for(it=array.begin();it !=array.end();it++){
        if(*it & 1){
            temp.push_back(*it);
//            cout << *it << endl;
        }
    }
    for(it=array.begin();it !=array.end();it++){
        if(!(*it & 1)){
            temp.push_back(*it);
//            cout << *it << endl;
        }
    }
    array = temp;

}

22 链表中倒数第 K 个结点

思路:设链表的长度为 N。设置两个指针 P1 和 P2,先让 P1 移动 K 个节点,则还有 N - K 个节点可以移动。此时让 P1 和 P2 同时移动,可以知道当 P1 移动到链表结尾时,P2 移动到第 N - K 个节点处,该位置就是倒数第 K 个节点。

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
    ListNode* front;
    ListNode* after;
    front = after = pListHead;
    while(k-- && front != NULL){
        front = front->next;
    }
    if(front == NULL && k!=-1){
        return NULL;
    }
    while(front != NULL){
        front = front->next;
        after = after->next;
    }
    return after;
}

23. 链表中环的入口结点

ListNode* EntryNodeOfLoop(ListNode* pHead)
{
    map<ListNode*,bool> m;
    ListNode* next;
    next = pHead;
    while(next != NULL && m.find(next) == m.end()){
        m[next] = true;
        next = next->next;
    }
    if(next == NULL){
        return NULL;
    }
    return next;
}

24. 反转链表

ListNode* ReverseList(ListNode* pHead) {
    ListNode* pre,*now,*next;
    pre = NULL;
    now = pHead;
    next = pHead->next;
    while(now!= NULL){
        now->next = pre;
        pre = now;
        now = next;
        next = next->next;
    }
    return pre;
}

25. 合并两个排序的链表

ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
    ListNode *now,*head;
    now = NULL;
    while(pHead1 != NULL && pHead2 != NULL){
        if(pHead1->val < pHead2->val){
            if(now == NULL){
                head = now = pHead1;
            }else{
                now->next = pHead1;
                now = pHead1;
            }
            pHead1 = pHead1->next;
        }else{
            if(now == NULL){
                head = now = pHead2;
            }else{
                now->next = pHead2;
                now = pHead2;
            }
            pHead2 = pHead2->next;
        }
    }
    while(pHead1 != NULL ){
        now->next = pHead1;
        now = pHead1;
        pHead1 = pHead1->next;
    }
    while(pHead2 != NULL ){
        now->next = pHead2;
        now = pHead2;
        pHead2 = pHead2->next;
    }
    return head;
}

26 树的子结构

{8,8,7,9,3,#,#,#,#,4,7},{8,9,2}成立

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
bool IsSubtree(TreeNode* pRoot1, TreeNode* pRoot2){

//    cout << "1" << endl;

    if(pRoot2 == NULL){
        //pRoot2为Null
        return true;
    }else if(pRoot1 == NULL ){
        //pRoot1为NULL
        return false;
    }

    if(pRoot1->val != pRoot2->val){
        //值不相等,直接false
        return false;
    }

    // 左右子树都相等
    if(IsSubtree(pRoot1->left, pRoot2->left)&&
            IsSubtree(pRoot1->right, pRoot2->right)
            ){
        return true;
    }
}

bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {

    if(pRoot1 == NULL || pRoot2 == NULL){
        return false;
    }
    if(pRoot1->val == pRoot2->val){
        if(IsSubtree(pRoot1,pRoot2)){
            return true;
        }
    }

    if(HasSubtree(pRoot1->left,pRoot2)){
        return true;
    }

    if(HasSubtree(pRoot1->right,pRoot2)){
        return true;
    }
    return false;
}

int main(){
    TreeNode* pRoot1,*pRoot2;
    pRoot1 = new TreeNode{8};
    pRoot1->left = new TreeNode{8};
    pRoot1->right =  new TreeNode{7};
    pRoot1->left->left = new TreeNode{9};
    pRoot1->left->right =  new TreeNode{3};
    pRoot1->left->right->left =  new TreeNode{4};
    pRoot1->left->right->right =  new TreeNode{7};

    pRoot2 = new TreeNode{8};
    pRoot2->left = new TreeNode{9};
    pRoot2->right =  new TreeNode{2};
    cout << HasSubtree(pRoot1,pRoot2);
    return 0;
}

27. 二叉树的镜像*

clipboard.png

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
void Swap(TreeNode* pRoot){
    TreeNode*  temp;
    temp = pRoot->left;
    pRoot->left = pRoot->right;
    pRoot->right = temp;

}

void Mirror(TreeNode *pRoot) {
    if(!pRoot) return;
    Swap(pRoot);
    Mirror(pRoot->left);
    Mirror(pRoot->right);
}

28. 对称的二叉树*

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

bool isSymmetrical(TreeNode* l,TreeNode* r){
    if(r == NULL && l == NULL)return true;
    else if(r == NULL || l == NULL) return false;
    else if(r->val != l->val) return false;

    return isSymmetrical(l->left,r->right) && isSymmetrical(l->right,r->left);
}

bool isSymmetrical(TreeNode* pRoot)
{
    if(!pRoot)return true;
    return isSymmetrical(pRoot->left,pRoot->right);
}

29. 顺时针打印矩阵*

clipboard.png

vector<int> printMatrix(vector<vector<int> > matrix) {
    int row,col;
    int mintimes;

    int rowend,colend;
    int rowstart,colstart;

    int i,j;

    vector<int> res;

    row = matrix.size();
    col = matrix[0].size();
    rowend = row-1;
    colend = col-1;
    rowstart = colstart = 0;

    mintimes = (min(row,col)+1)/2;
    i = j = 0;
//    cout << "done";
    while(rowstart <= rowend||colstart <= colend ){
        // 往右
        i = rowstart;
        j = colstart;
        while(j <= colend){
//            cout << matrix[i][j]<< endl;
            res.push_back(matrix[i][j++]);
        }
        rowstart++;
        if(rowstart > rowend||colstart > colend){
            break;
        }

        // 往下
        i = rowstart;
        j = colend;
        while(i <= rowend){
//            cout << matrix[i][j] << endl;
            res.push_back(matrix[i++][j]);
        }
        colend--;
        if(rowstart > rowend||colstart > colend){
            break;
        }
        // 往左
        i = rowend;
        j = colend;
        while(j >= colstart){
//            cout << matrix[i][j]<< endl;
            res.push_back(matrix[i][j--]);
        }
        rowend--;
        if(rowstart > rowend||colstart > colend){
            break;
        }
        // 往上
        i = rowend;
        j = colstart;
        while(i >= rowstart){
//            cout << matrix[i][j]<< endl;
            res.push_back(matrix[i--][j]);
        }
        colstart++;
        if(rowstart > rowend||colstart > colend){
            break;
        }
    }
    return res;
}
int main(){
    vector<int> a{1,2,3,4};
    vector<int> b{5,6,7,8};
    vector<int> c{9,10,11,12};
    vector<int> d{13,14,15,16};
    vector<int> res;
    vector<vector<int>> All{a,b,c,d};
    vector<int>::iterator it;
    res = printMatrix(All);
    for(it = res.begin();it != res.end();it++){
        cout << *it << " ";
    }
//    cout << "done " << endl;

}

30. 包含 min 函数的栈


stack<int> data;
stack<int> mi;

void push(int value) {
    data.push(value);
    mi.push(mi.empty()?value:min(value,mi.top()));
    std::
}
void pop() {
    data.pop();
    mi.pop();
}
int top() {
    return data.top();
}
int min() {
    return mi.top();
}

31. 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

bool IsPopOrder(vector<int> pushV,vector<int> popV) {
    int pushVstart,pushVend;
    int popVstart,popVend;
    pushVstart = 0;
    pushVend = pushV.size()-1;
    popVstart = popV.size()-1;
    popVend = 0;
    while(pushVstart <= pushVend){
        if(pushV[pushVstart] == popV[popVstart]){
            pushVstart++;
            popVstart--;
        }else if(pushV[pushVstart] ==popV[popVend]){
            pushVstart++;
            popVend++;
        }else{
            return false;
        }
    }
    return true;

}

32.1 层序遍历树

vector<int> PrintFromTopToBottom(TreeNode* root) {
        queue<TreeNode*> que;
        vector<int> vt;
        if(!root)return vt;
        TreeNode* t;

        que.push(root);
        while(!que.empty()){
            t = que.front();
            vt.push_back(t->val);
            //cout << t->val << " ";
            que.pop();
            if(t->left) que.push(t->left);
            if(t->right) que.push(t->right);
        }
        return vt;
    }

32.3 按之字形顺序打印二叉树*

如果当前是往左的,左子树先进栈.如果是往右的,右子树先进栈.



struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};

vector<vector<int>> Print(TreeNode* pRoot) {
    vector<vector<int>> vt;
    stack<TreeNode*> st;
    bool isleft;
    TreeNode* t;
    if(!pRoot) return vt;

    st.push(pRoot);
    isleft = true;
    while(!st.empty()){
        vector<int> vtemp;
        // 临时栈
        stack<TreeNode*> stemp;
        while(!st.empty()){
            t = st.top();
            vtemp.push_back(t->val);
            st.pop();
            if(isleft){
//                如果当前方向是左,左子节点先入
                if(t->left)stemp.push(t->left);
                if(t->right)stemp.push(t->right);
            }else{
                if(t->right)stemp.push(t->right);
                if(t->left)stemp.push(t->left);
            }
        }
//        改变方向
        isleft = !isleft;
        vt.push_back(vtemp);
        st = stemp;
    }
    return vt;
}
int main(){
    TreeNode* pRoot1,*pRoot2;
    vector<vector<int>> res;
    pRoot1 = new TreeNode{8};
    pRoot1->left = new TreeNode{8};
    pRoot1->right =  new TreeNode{7};
    pRoot1->left->left = new TreeNode{9};
    pRoot1->left->right =  new TreeNode{3};
    pRoot1->right->left =  new TreeNode{1};
    pRoot1->right->right =  new TreeNode{2};
    pRoot1->right->left->left =  new TreeNode{3};
    pRoot1->right->left->right =  new TreeNode{4};
    pRoot1->left->right->left =  new TreeNode{4};
    pRoot1->left->right->right =  new TreeNode{7};
    res = Print(pRoot1);
    for(vector<vector<int>>::iterator it=res.begin();it != res.end();it++){
        for(vector<int>::iterator jt = (*it).begin();jt != (*it).end();jt++){
            cout << *jt << endl;
        }
    }

33 二叉搜索树的后序遍历序列**

反证法,假设是二叉搜索树。
可以知道最后一个是根节点。找到第一个比根节点大的值,这个值往后的值都是右子树,前面的都是左子树。
也就是这个值的后面都要比根节点大。这样层层递归下去。变可知答案。

int flag = false;
bool VerifySquenceOfBST(vector<int> sequence) {
    int root = sequence.size()-1;
    int i = 0;
    vector<int> left,right;
    if(flag == false && sequence.size() == 0) return false;
    flag = true;
//    cout << "root" << root << endl;
    // 找到第一个大于根节点的位置。
//    cout << 4 << endl;
    if(sequence.size()<=1) return true;
//    cout << 3 << endl;
    while(sequence[i] < sequence[root]){
        i++;
        // 左子树
        left.push_back(sequence[i]);
    }
    // 判断右子树是不是全部都比其大。
//    cout << 2 << "i:" << i << endl;
    while(i < root && sequence[i] > sequence[root]){
        i++;
        //右子树
        right.push_back(sequence[i]);
    }
//    cout << 1 << "i:" << i << endl;
    if(i != root){
        return false;
    }
    return VerifySquenceOfBST(left) && VerifySquenceOfBST(right);
}

34 二叉树中和为某一值的路径

vector<int> vtemp;
void FindDFS(TreeNode* root,int expectNumber,vector<vector<int>> &res){
    if(!root)return;
    if(root->left == NULL
       && root->right == NULL
       && root->val == expectNumber){
        vtemp.push_back(root->val);
        res.push_back(vtemp);
        vtemp.pop_back();
        return;
    }
    vtemp.push_back(root->val);
    FindDFS(root->left,expectNumber-root->val,res);
    FindDFS(root->right,expectNumber-root->val,res);
    vtemp.pop_back();
}
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
    vector<vector<int>> res;
    FindDFS(root,expectNumber,res);
    return res;
}

35 复杂链表的复制**

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 head。

clipboard.png


解题思路:
第一步,在每个节点的后面插入复制的节点
clipboard.png
第二步,对复制节点的 random 链接进行赋值

clipboard.png

第三步,拆分

clipboard.png


struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
//法一
//map<RandomListNode*,RandomListNode*> m1;
//RandomListNode* Clone(RandomListNode* pHead){
//    RandomListNode* t = pHead;
//    while(t!=NULL){
//        m1[t] = new RandomListNode(t->label);
//    }
//    t = pHead;
//    while(t!=NULL){
//        m1[t]->next = m1[t->next];
//        m1[t]->random = m1[t->random];
//    }
//    return m1[pHead];
//}

RandomListNode* Clone(RandomListNode* pHead) {
    RandomListNode *t = pHead;
    RandomListNode *next,*copyHead;
    if(pHead == NULL) return NULL;
//    复制
    while (t != NULL) {
        next = t->next;
        t->next = new RandomListNode(t->label);
        t->next->next = next;
        t = next;
    }
//    random复制
    t = pHead;
    copyHead = pHead->next;
    while (t != NULL) {
        next = t->next->next;
        if(t->random != NULL)t->next->random = t->random->next;
        t = next;
    }
//    拆分
    t = pHead;
    next = t->next->next;
    while (t != NULL && next != NULL) {
        t->next->next = next->next;
        t->next = next;
        t = next;
        next = t->next->next;
    }
    t->next = NULL;
    return copyHead;
}

int main(){
    RandomListNode* r1,*res;
    r1 = new RandomListNode{1};
    r1->next = new RandomListNode{2};
    r1->next->next = new RandomListNode{3};
    res = Clone(r1);
    while(res != NULL){
        cout << res->label << " ";
        res =res->next;
    }
}

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

36 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

clipboard.png


struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
TreeNode*pre = NULL;
TreeNode*head = NULL;
void InTraver(TreeNode* pRootOfTree){
    if(pRootOfTree == NULL){
        return;
    }
    InTraver(pRootOfTree->left);
    pRootOfTree->left = pre;
    if(!head) head = pRootOfTree;
    if(pre !=NULL){
        pre->right = pRootOfTree;
    }
    pre = pRootOfTree;
    InTraver(pRootOfTree->right);

}
TreeNode* Convert(TreeNode* pRootOfTree){
    InTraver(pRootOfTree);
    return head;
}
int main(){
    TreeNode* pRoot1,*pRoot2;
//    vector<vector<int>> res;
    TreeNode* res;
    pRoot1 = new TreeNode{8};
    pRoot1->left = new TreeNode{6};
    pRoot1->right =  new TreeNode{10};
//    pRoot1->left->left = new TreeNode{4};
//    pRoot1->left->right =  new TreeNode{7};
//    pRoot1->right->left =  new TreeNode{11};
//    pRoot1->right->right =  new TreeNode{12};
    res = Convert(pRoot1);
    while(res){
        cout << res->val << " " ;
        res = res->right;
    }

}

37 序列化二叉树*

请实现两个函数,分别用来序列化和反序列化二叉树

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。



char res[1000]{0};

// 先序遍历迭代生成
char* Serialize(TreeNode *root) {
//    if(!root)return NULL;
    stack<char> stchar;
    if(!root){
        res[strlen(res)] = '#';
        return res;
    }else{
        int temp = root->val;
        while(temp){
            stchar.push(char(temp%10+48));
            temp /= 10;
        }
        while(!stchar.empty()){
            res[strlen(res)] = stchar.top();
            stchar.pop();
        }
        res[strlen(res)] = '!';
    }
    Serialize(root->left);
    Serialize(root->right);
    return res;
}


TreeNode* Deserialize(char *str) {
    stack<TreeNode**> stNode;
    int data=0;
    if(str == NULL && *str == '#'){
        return NULL;
    }
    TreeNode* nowNode,*Root;
    Root =NULL;
    // 取数
    while(*str) {
        data = 0;
        if (*str != '#') {
            // 解析字符串
            while (*str != '!') {
                data = data * 10 + (*str - 48);
                str++;
            }
            nowNode = new TreeNode{data};
            if(!Root) Root = nowNode;

            if (!stNode.empty()) {
                // 父亲认领
                TreeNode** temp;
                temp=stNode.top();
                *temp = nowNode;
                stNode.pop();
            }
            // 当前节点的孩子的指针入栈
            stNode.push(&nowNode->right);
            stNode.push(&nowNode->left);
        } else {
            if (!stNode.empty()) {
                // 父亲认领
                TreeNode** temp;
                temp=stNode.top();
                *temp = NULL;
                stNode.pop();
            }else{
                cout << "bug" <<endl;
            }
        }
        str++;// 摆脱!和#
    }
    memset(res,0,1000);
    return Root;
}

38 字符串的排列**

利用全排列的非递归算法可以自动去重
解题算法:

  1. 先将字符串按从小到大排列
  2. 从end往前找到第一个连续递增,记为i,ii,其中i == ii-1
  3. 从[ii,end]中以<---该方向找第一个比[i]大的,下标设为x
  4. i的值互换
  5. reverse(ii,end) -----<algorithm>包
  6. 回到2,直到全部递减退出循环.

vector<string> res;
//int debug = 0;
vector<string> Permutation(string str) {
    string::iterator i,ii,x;
    sort(str.begin(),str.end());
    if(str == ""){
        return res;
    }

    res.push_back(str);
    while(true){
//        debug ++;
        i = str.end() -2;
        ii = i+1;
        // 从后边找,找到第一个递增的。
        while(ii != str.begin() && *i >= *ii){i--;ii--;};
        // 退出判断
        if(ii == str.begin()) break;
        // 从[ii,end)中按此方向<---找到第一个比str[i]大的,设为x
        x = --str.end();
        while(*x<=*i){
            // 最多遍历到ii.
            x--;
        }
        // str[i]str[x]互换
        char swapTemp;
        swapTemp = *i;
        *i = *x;
        *x = swapTemp;
        // Reverse(ii,end)
        reverse(ii,str.end());
        res.push_back(str);
    }
    return res;
}

39 数组中出现次数超过一半的数字**

int MoreThanHalfNum_Solution(vector<int> numbers) {
    int candidate,count;
    int sum;
    candidate = numbers[0];
    count = 1;
    for(int i=1; i < numbers.size();i++){
        count = numbers[i] == candidate?++count:--count;
        if(count == 0){
            candidate = numbers[i];
            count = 1;
        }
    }
//    cout << candidate;
    sum = 0;
    for(int i = 0;i < numbers.size();i++){
        if(candidate == numbers[i]) sum++;
    }
    return sum>numbers.size()/2?candidate:0;
}

40 最小的 K 个数*

堆排序


// i是当前节点,n是节点数
void MaxHeapFixDown(vector<int>& input,int parent,int n){
    int kid;
    kid = parent*2 +1;
    while(kid < n){
        if((kid+1<n)&&(input[kid] < input[kid+1])){
            kid ++;
        }
        if(input[parent] < input[kid]){
            input[parent] ^= input[kid];
            input[kid] ^= input[parent];
            input[parent] ^= input[kid];
        }else{
            return;
        }
        parent = kid;
        kid = parent*2 +1;
    }
//    for(vector<int>::iterator it = input.begin();it != input.end();it++){
//        cout << *it << " ";
//    }
    cout << endl;
    return;
}
// 大顶堆生成
void CreateMaxHeap(vector<int>& input){
    int maxNode = input.size()/2 - 1;
    while(maxNode>=0){
        MaxHeapFixDown(input,maxNode,input.size());
        maxNode--;
    }
}

void HeapSort(vector<int>& input){
    CreateMaxHeap(input);
    for(int i = input.size()-1;i>0;i--){
        input[i] ^= input[0];
        input[0] ^= input[i];
        input[i] ^= input[0];
        MaxHeapFixDown(input,0,i-1);
//        for(vector<int>::iterator it = input.begin();it != input.end();it++){
//            cout << *it << " ";
//        }
    }
}


vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {

    vector<int>res;
    if(input.size() == 0 || input.size()<k){
        return res;
    }
    HeapSort(input);
    for(int i = 0;i < k;i++){
        res.push_back(input[i]);
    }
    return res;
}
int main(){
    int a[]{4,5,1,6,2,7,3,8};
    vector<int> res;
    vector<int>input(a,a+sizeof(a)/sizeof(a[0]));
    res = GetLeastNumbers_Solution(input,4);
    for(vector<int>::iterator it = res.begin();it != res.end();it++){
        cout << *it << " ";
    }
}

41.1 数据流中的中位数**

使用两个优先数组。

struct mycmp{
    bool operator()(const int &a,const int &b){
        return a > b;
    }
};

priority_queue<int,vector<int>,mycmp> pqright;
priority_queue<int> pqleft;
int n = 0;

void Insert(int num)
{
    if(n % 2 == 0){
        pqleft.push(num);
        pqright.push(pqleft.top());
        pqleft.pop();
    }else{
        pqright.push(num);
        pqleft.push(pqright.top());
        pqright.pop();
    };
    n++;
}

double GetMedian()
{
    if(n == 0){
        return 0;
    }
    if(n % 2 == 0){
//        cout << pqright.top() << " " << pqleft.top() << endl;
        return (pqright.top()+pqleft.top())/2.0;
    }else{
        return double(pqright.top());
    }
}

41.2 字符流中第一个不重复的字符**

queue<char> q;
map<char,int> m;
//Insert one char from stringstream
void Insert(char ch)
{
    if(m.find(ch) != m.end()){
        // 如果已经有过了
        m[ch]++;
        while(!q.empty() && m[q.front()] > 1){
            q.pop();
        }
    }else{
        m[ch]=1;
        q.push(ch);
    }

}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
    if (q.empty()){
        return '#';
    }else{
        return q.front();
    }
}

42. 连续子数组的最大和

int FindGreatestSumOfSubArray(vector<int> array) {
    int resmax=INT_MIN;
    int record=0;
    for(int i=0;i < array.size();i++){
       
        if(array[i] >= 0 && record<0){
            record = 0;
        }
        record += array[i];
         if(resmax < array[i]||resmax < record){
            resmax = max(array[i],record);
        }
    }
    return resmax;
}

43. 从 1 到 n 整数中 1 出现的次数**

排列组合思想
https://blog.csdn.net/huzhige...

int NumberOf1Between1AndN_Solution(int n)
{
    int low = 0;
    int temp = n,t;
    int p=1;
    int res=0;
    while(temp){
        t = temp % 10;
        temp/=10;
        if(t == 0){
            res += temp*p;
        }else if(t == 1){
            res += temp*p+low+1;
        }else{
            res += (temp+1)*p;
        }
        low = low+t*p;
        p*=10;
    }
    return res;
}

45. 把数组排成最小的数

struct mycmp{
    bool cmp(string&a,string&b){
        if(a+b > b+a){
            return false;
        }else {
            return true;
        }
    }
};



string PrintMinNumber(vector<int> numbers) {
    vector<string> numstr;
    int i;
    int inttemp;
    string res;
    string strtemp;
    char chartemp;
    // 转字符串
    for(i = 0;i < numbers.size();i++){
        inttemp = numbers[i];
        strtemp ="";
        while(inttemp){
            chartemp = '0' + inttemp%10;
//            strtemp = ""+ chartemp + strtemp;
            strtemp.insert(0,1,chartemp);
            inttemp/=10;
        }
        numstr.push_back(strtemp);
    }

    // 排序
    sort(numstr.begin(),numstr.end(),cmp);
    for(vector<string>::iterator it = numstr.begin();it != numstr.end();it++){
        res += *it;
    }
    return  res;
}

46. 把数字翻译成字符串


map<string,string> m1;
void makemap(){
    string start2 = "A";
    string start1 = "0";
    int i=0;
    while(i != 26){
        if(start1[start1.length()-1]+1 >'9'){
            if(start1.length() == 1) start1 = "10";
            else{
                start1[0]+=1;
                start1[1] = '0';
            }
        }else{
            start1[start1.length()-1]+=1;
        }
        m1[start1] = start2;
//        cout << start1 << " " << start2 << endl;
        start2[0]+=1;
        i++;
    }
}
int res = 0;
void dfs(string s){
    if(s == ""){
        res ++;
        return;
    }
    string tempstr,substr;
    if(m1.find(s.substr(0,1)) != m1.end()){
        dfs(s.substr(1));
    }
    if(s.length() > 1&& m1.find(s.substr(0,2)) != m1.end()){
        dfs(s.substr(2));
    }
}
int numDecodings(string s) {
    dfs(s);
    return res;
}

47. 礼物的最大价值

简单的动态规划


int dp[6][6]{0};
int getMost(vector<vector<int> > board) {
    // write code here
    int i,j;
    i = 0;
    for(j = 0;j < 6;j++){
        if(j == 0) dp[i][j] = board[i][j];
        else dp[i][j] = dp[i][j-1] + board[i][j];
    }
    j=0;
    for(i = 0;i < 6;i++){
        if(i == 0) dp[i][j] = board[i][j];
        else dp[i][j] = dp[i-1][j]+board[i][j];
    }

    for(i = 1;i<6;i++){
        for(j = 1;j < 6;j++)
            dp[i][j] = max(board[i][j]+dp[i-1][j],board[i][j]+dp[i][j-1]);
    }
    return dp[5][5];
}

49. 丑数**

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。


int dp[10000];
int GetUglyNumber_Solution(int index) {
    // 记录乘以2,3,5,前一个数
    int *dp = new int(index);
    dp[0] = 1;
    i2 = i3 = i5 = 0;
    for(int i = 1;i < index;i++){
        dp[i] = min(dp[i2]*2,min(dp[i3]*3,dp[i5]*5));
//        不能用if else ;会出现6多次
        if(dp[i] == dp[i2]*2){
            i2++;
        }
        if(dp[i] == dp[i3]*3){
            i3++;
        }
        if(dp[i] == dp[i5]*5) {
            i5++;
        }
    }
    return dp[index-1];

}

l1nkkk
33 声望6 粉丝