剑指offer题目

1.二叉树镜像


python:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        if root == None:
            return 
        self.Mirror(root.left)
        self.Mirror(root.right)
        root.left,root.right = root.right,root.left

C++:

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    void Mirror(TreeNode *pRoot) {
    if (pRoot) {
        Mirror(pRoot->left);
        Mirror(pRoot->right);
        TreeNode *temp=pRoot->left;
        pRoot->left=pRoot->right;
        pRoot->right=temp;
    }
    }
};

2.判断链表中是否包含环,输出环入口节点,否则输出NULL

思路:
该题使用一种巧妙的方法,使用两个步长分别是1和2的指针


python

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        if pHead== None or pHead.next == None:
            return None
        fast = slow = pHead
        while(fast and fast.next):
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                fast = pHead
                while(fast!=slow):
                    fast = fast.next
                    slow = slow.next
                return fast
        return None

C++

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if ((pHead->next==NULL)||(pHead==NULL)) return NULL;
        ListNode* fast = pHead;
        ListNode* slow = pHead;
        bool isCycle = false;

        while((fast!=NULL)&&(slow!=NULL)){
            fast=fast->next;
            slow=slow->next;
            if (fast->next==NULL)return NULL;
            fast=fast->next;
            if(fast==slow){isCycle=true;break;}
        }
        if(!isCycle)return NULL;
        fast=pHead;
        while(fast!=slow){
            fast=fast->next;
            slow=slow->next;
        }
        return fast;
    }
};

3.删除链表重复节点

python

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        if(pHead==None):
            return None
        if(pHead.next==None):
            return pHead
        val = pHead.val
        p = pHead.next
        if(val!=p.val):
            pHead.next=self.deleteDuplication(p)
            return pHead
        else:
            while (p and (val==p.val)):
                p=p.next
            return self.deleteDuplication(p)

c++

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if (!pHead) return 0;
        if (!pHead->next) return pHead;

        int val = pHead->val;
        ListNode* p = pHead->next;

        if (p->val != val) {
            pHead->next = deleteDuplication(p);
            return pHead;
        } else {
            while (p && p->val == val) p = p->next;
            return deleteDuplication(p);
        }
    }
};

4.反转链表

使用python array与c++ STL自带的reverse函数即可


python

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        ret = []
        head = listNode
        while(head):
            ret.append(head.val)
            head = head.next
        ret.reverse()
        return ret

c++

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> myvector;
        while(head!=NULL){myvector.push_back(head->val);head=head->next;}
        reverse(myvector.begin(),myvector.end()); 
        return myvector;
    }
};

5.斐波那契数列


python

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n==0:
            return 0;
        elif n==1:
            return 1;
        else:
            a0=0;
            a1=1;
            for i in range(n-1):
                a2=a0+a1;
                a0=a1;
                a1=a2;
            return a2

C++

class Solution {
public:
    int Fibonacci(int n) {
        if (n ==0) return 0;
        else if(n == 1) return 1;
        else{
            int a0 = 0;
            int a1 = 1;
            int a2;
            for (int i=0;i<n-1;i++){
                a2 = a0 + a1;
                a0 = a1;
                a1 = a2;
            }
            return a2;
        }
    }
};

6.青蛙跳台阶,一次跳1或2阶,共n阶,几种跳法

思路:
f(1)=1
f(2)=2

f(n)=f(n-1)+f(n-2)
注意:递归效率低,重复调用函数,尽量使用迭代。


python

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number==1:
            return 1
        elif number==2:
            return 2
        else:
            a0=1
            a1=2
            for i in range(number-2):
                a2=a0+a1
                a0=a1
                a1=a2
            return a2

c++

class Solution {
public:
    int jumpFloor(int number) {
        if (number==0)return 0;
        else if (number==1)return 1;
        else if (number==2)return 2;
        else
            return jumpFloor(number-1)+jumpFloor(number-2);
    }
};

7.变态跳台阶,一次可以跳1~n阶

思路:
f(1)=1
f(2)=f(1)+1
f(3)=f(2)+f(1)+1=2*f(2)

f(n)=2*f(n-1)


python

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        a0=1
        for i in range(number-1):
            a0=a0*2
        return a0

C++

class Solution {
public:
    int jumpFloorII(int number) {
        int a0 = 1;
        for(int i=0;i<number-1;i++){
            a0=a0*2;
        }
        return a0;
    }
};

8.矩阵覆盖

用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法
思路:依旧斐波那契


python

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        if number==1:
            return 1
        elif number==2:
            return 2
        elif number==0:
            return 0
        else:
            a0=1
            a1=2
            for i in range(number-2):
                a2=a0+a1
                a0=a1
                a1=a2
            return a2

c++

class Solution {
public:
    int rectCover(int number) {
        if(number==1)return 1;
        else if(number==2)return 2;
        else if(number==0)return 0;
        else{
            int a0=1;
            int a1=2;
            int a2;
            for(int i=0;i<number-2;i++){
                a2=a0+a1;
                a0=a1;
                a1=a2;
            }
            return a2;
        }
    }
};

9.字符串转整数

将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0


python

# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        # write code here
        symbol=1
        num=0
        if s=='':
            return 0
        for i in s:
            if i=='+':
                symbol=1
            elif i=='-':
                symbol=-1
            elif i>'0' and i<'9':
                num=num*10+int(i)
            else:
                return 0
        return symbol*num

c++

class Solution {
public:
    int StrToInt(string str) {
        int symbol = 1;
        int num=0;
        for (int i=0;i<str.size();i++){
            if (str[i]=='+')symbol=1;
            else if(str[i]=='-')symbol=-1;
            else if((str[i]>'0')&&(str[i]<'9'))num=num*10+(str[i]-'0');
            else return 0;
        }
        return symbol*num;
    }
};

10.平衡二叉树的判断

思路:BST的定义为|height(lefttree)−height(righttree)|<=1且两个子树均为BST,原问题拆分为计算树高度和判断高度差


python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        # write code here
        if pRoot==None:
            return True
        h1=self.Get_Tree_Height(pRoot.left)
        h2=self.Get_Tree_Height(pRoot.right)
        if(h1-h2)<=1 and(h2-h1)<=1:
            return True
        else:
            return False
    def Get_Tree_Height(self, pRoot):
        if pRoot==None:
            return 0
        else:
            return max(self.Get_Tree_Height(pRoot.left),self.Get_Tree_Height(pRoot.right))+1

c++

class Solution {
public:
    int TreeDepth(TreeNode *pRoot)
{
    if (pRoot == NULL)
        return 0;
    int left = TreeDepth(pRoot->left);
    int right = TreeDepth(pRoot->right);

    return (left > right) ? (left + 1) : (right + 1);
}

    bool IsBalanced_Solution(TreeNode* pRoot) {
    if (pRoot == NULL)
        return true;

    int left = TreeDepth(pRoot->left);
    int right = TreeDepth(pRoot->right);
    int diff = left - right;
    if (diff > 1 || diff < -1)
        return false;

    return IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right);
    }
};

11.和为S的连续正数序列

输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思考:S%奇数==0 或者S%偶数==偶数/2 就说明有这个连续序列,但是注意是正数序列,可能会出现越界情况


python

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        # write code here
        k = 2
        ret = []
        for k in range(2,tsum):
            if k%2==1 and tsum%k==0:
                tmp = []
                mid = tsum/k
                if mid-k/2>0:
                    for i in range(mid-k/2,mid+k/2+1):
                        tmp.append(i)
                    ret.append(tmp[:])
            elif k%2==0 and (tsum%k)*2==k:
                mid = tsum/k
                tmp = []
                if mid-k/2+1>0:
                    for i in range(mid-k/2+1,mid+k/2+1):
                        tmp.append(i)
                    ret.append(tmp[:])
        ret.sort()
        return ret

c++

class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        int l = 1,r = 1,sumx = 1;
        vector<vector<int> > ans;
        while(l <= r){
            r ++;
            sumx += r;
            while(sumx > sum){
                sumx -= l;
                l ++;
            }
            if(sumx == sum && l != r){
                vector<int> tmp;
                for(int i = l;i <= r;i ++)  tmp.push_back(i);
                ans.push_back(tmp);
            }
        }
        return ans;
    }
};

12.左旋转字符串

对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。


python

# -*- coding:utf-8 -*-
class Solution:
    def LeftRotateString(self, s, n):
        # write code here
        if s=='':
            return s
        mov=n%len(s)
        news=s[mov:]+s[:mov]
        return news

c++

class Solution {
public:
    string LeftRotateString(string str, int n) {
        int lstr=str.size();
        if (lstr==0)return str;
        int mov=n%lstr;
        string newstr;
        for(int i = mov;i<lstr;i++)newstr.push_back(str[i]);
        for(int i = 0;i<mov;i++)newstr.push_back(str[i]);
        return newstr;
    }
};

13.数字在排序数组中出现的次数

思路:二分查找


python

# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        start = 0
        end = len(data)-1
        while(start<=end):
            mid = (start+end)/2
            if data[mid]==k:
                cnt = 0
                tmp = mid
                while(tmp>=0 and data[tmp]==k):
                    cnt+=1
                    tmp-=1
                tmp = mid+1
                while(tmp<len(data) and data[tmp]==k):
                    cnt+=1
                    tmp+=1
                return cnt
            elif data[mid]>k:
                end = mid-1
            else:
                start = mid+1
        return 0

C++

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.size()==0)return 0;
        int len=data.size();
        int KeyIndex=0;
        KeyIndex=BinarySearch(data,0,len-1,k);
        if(KeyIndex==-1) return 0;
        int sumber=1;
        int m=KeyIndex-1;
        int n=KeyIndex+1;

       while(m>=0&&data[m]==k)
        {
                m--;sumber++;
            }
        while(n<len&&data[n]==k)
        {
               n++; sumber++;
            }
        return sumber;
    }
    int BinarySearch(vector<int> data, int low, int high, int k){
        while (low<=high){
        int m = (high + low) / 2;
        if (data[m] == k)return m;
        else if (data[m] < k) low = m+ 1;
        else high = m - 1;}
        return -1;
    }
};

14.数组中只出现一次的数字

思路:在其他题目中,要求时间复杂度为O(n),排除先排序;空间复杂度要求O(1),排除hash思路。考虑到对于一个int类型变量a,a与0的异或为本身,与自身的异或为0,因此可以将所有数字依次异或,这样偶数次数的数字被消除,仅剩一次的数字。但本题中有两个这样的数字,因此需要将两个数字分离成两堆。在将所有数字异或后,所得结果即所求两个数字的异或值,因此可从两个数字的异或值中第一位不是0的位出手,将所有数字根据此位是否为1分为两堆,两堆分别求异或值结果即所求两数。


python

class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        ans,a1,a2,flag= 0,0,0,1
        for num in array:
            ans = ans ^ num
        while(ans):
            if ans%2 == 0:
                ans = ans >>1 
                flag = flag <<1
            else:
                break
        for num in array:
            if num & flag:
                a1 = a1 ^ num
            else:
                a2 = a2 ^ num
        return a1,a2

c++

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if (data.size() < 2)
        return;
        int resultExclusiveOR = 0;
        for (int i = 0; i < data.size(); ++ i)
            resultExclusiveOR ^= data[i];
        unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR); 
        *num1 = *num2 = 0;
        for (int j = 0; j < data.size(); ++ j){
            if(IsBit1(data[j], indexOf1))
            *num1 ^= data[j];
            else
            *num2 ^= data[j];
    }
    }
    unsigned int FindFirstBitIs1(int num){
        int indexBit = 0;
        while (((num & 1) == 0) && (indexBit < 32)){
            num = num >> 1;
            indexBit++;}
        return indexBit;
    }
    bool IsBit1(int num, unsigned int indexBit){
        num = num >> indexBit;
        return (num & 1);}
};

15.翻转单词顺序列

将句子中由空格间隔的各词汇顺序翻转。


python

# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        ret = s.split(" ")
        ret.reverse()
        return ' '.join(ret)

c++

class Solution {
public:
     string ReverseSentence(string str) {
        int len = str.size();
        int start = 0;
        for(int i = 0; i < len; i ++){
             if(str[i] == ' '){
                 reverse(str.begin()+start, str.begin()+i);
                 start = i+1;
             }
        if(i == len-1){
            reverse(str.begin()+start, str.end());
        }
        }
        reverse(str.begin(), str.end());
        return str;
    }
};

16.二叉树深度

python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if(pRoot==None):
            return 0
        h1 = self.TreeDepth(pRoot.left);
        h2 = self.TreeDepth(pRoot.right);
        if h1>h2:
            return h1+1
        else:
            return h2+1

c++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if (pRoot==NULL)return 0;
        int depth1 = TreeDepth(pRoot->left);
        int depth2 = TreeDepth(pRoot->right);
        int depth = (depth1 > depth2 ? depth1 : depth2)+1;
        return depth;
    }
};

17.和为S的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
思路:采用两个指针分别从数组两端向中间推进,最先满足条件的两个数乘积最小。


python

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        a1=0
        a2=-1
        while(a1-a2<len(array)):
            if(array[a1]+array[a2]<tsum):
                a1+=1
            elif(array[a1]+array[a2]>tsum):
                a2-=1
            else:
                return [array[a1],array[a2]]
        return[]

c++

class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        int len = array.size();
        vector<int>twonum;
        if (len<=1)return twonum;
        int v1=0,v2=len-1;

        while(v1!=v2){
            if((array[v1]+array[v2])<sum)v1++;
            else if((array[v1]+array[v2])>sum)v2--;
            else {twonum.push_back(array[v1]);twonum.push_back(array[v2]);break;}
        }
        return twonum;
    }
};

18.顺时针打印矩阵

python

# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        m=len(matrix)
        ans=[]
        if m==0:
            return ans
        n=len(matrix[0])
        w1=0;w2=n-1;h1=0;h2=m-1;
        while(True):
            if((w1>w2)or(h1>h2)):
                break;
            for i in range(w1,w2+1):
                ans.append(matrix[h1][i])
            h1=h1+1
            if((w1>w2)or(h1>h2)):
                break;
            for i in range(h1,h2+1):
                ans.append(matrix[i][w2])
            w2=w2-1
            if((w1>w2)or(h1>h2)):
                break;
            for i in range(w1,w2+1):
                ans.append(matrix[h2][n-2-i])
            h2=h2-1
            if((w1>w2)or(h1>h2)):
                break;
            for i in range(h1,h2+1):
                ans.append(matrix[m-1-i][w1])
            w1=w1+1
        return ans

c++

class Solution {
public:
    vector<int> printMatrix(vector<vector<int>> matrix) {
        int row=matrix.size();
        int col=matrix[0].size();
        vector<int> result;
        if(row==0||col==0)
            return result;
        int left=0,right=col-1,top=0,btm=row-1;
        while(left<=right&&top<=btm)
            {
            for(int i=left;i<=right;i++)
                result.push_back(matrix[top][i]);
            if(top<btm)
                for(int i=top+1;i<=btm;i++)
                    result.push_back(matrix[i][right]);
            if(top<btm&&left<right)
                for(int i=right-1;i>=left;i--)
                    result.push_back(matrix[btm][i]);
            if(top+1<btm&&left<right)
                for(int i=btm-1;i>=top+1;i--)
                    result.push_back(matrix[i][left]);
            left++;right--;top++;btm--;
        }
        return result;
    }
};

19.二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:中序遍历,根据其是否含有右子树、若无则返回父节点等系列条件判断
python

class Solution:
    def GetNext(self, pNode):
        # write code here
        # left root right
        if pNode == None:
            return None
        if pNode.right:
            tmp = pNode.right
            while(tmp.left):
                tmp = tmp.left
            return tmp
        p = pNode.next
        while(p and p.right==pNode):
            pNode = p
            p = p.next
        return p

c++

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {

    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode->right!=NULL){
            TreeLinkNode *temp=pNode->right;
            while(temp->left!=NULL)temp=temp->left;
            return temp;
        }
        else{
            TreeLinkNode *temp=pNode;
            while(temp->next!=NULL){
                if(temp==temp->next->left)return temp->next;
                else{temp=temp->next;}
            }
            return NULL;
        }
    }
};

20.对称的二叉树

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


python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        if pRoot==None:
            return True
        return self.isSame(pRoot.right,pRoot.left)
    def isSame(self,t_left,t_right):
        if(t_left==None)and(t_right==None):
            return True
        elif(t_left!=None)and(t_right==None):
            return False
        elif(t_left==None)and(t_right!=None):
            return False
        else:
            result = True
            result = result and self.isSame(t_left.left,t_right.right)
            result = result and self.isSame(t_left.right,t_right.left)
            result = result and (t_left.val==t_right.val)
            return result

C++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        return isSymmetrical(pRoot,pRoot);
    }
    bool isSymmetrical(TreeNode* pRoot1,TreeNode* pRoot2)
    {
        if(pRoot1==nullptr&&pRoot2==nullptr)
            return true;
        if(pRoot1==nullptr||pRoot2==nullptr)
            return false;
        if(pRoot1->val!=pRoot2->val)
            return false;
        return isSymmetrical(pRoot1->left,pRoot2->right)&& isSymmetrical(pRoot1->right,pRoot2->left);
    }

};

21.逐行打印二叉树

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
思路:此题在于灵活使用队列这一数据结构。将本层的结点全部push后,记录结点数目,每打印一个结点就pop一个,同时将该节点的左右子树结点push。在c++中,使用queue数据结构。在python中,则使用列表的append、pop(0)。


python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if not pRoot:
            return []
        res=[]
        tmp=[pRoot]
        while tmp:
            size=len(tmp)
            row=[]
            for i in tmp:
                row.append(i.val)
            res.append(row)
            for i in range(size):
                node=tmp.pop(0)
                if node.left:
                    tmp.append(node.left)
                if node.right:
                    tmp.append(node.right)
        return res

c++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int>>result;
            if(pRoot==NULL)return result;
            queue<TreeNode*>q;
            q.push(pRoot);
            while(q.size()!=0){
                int len=q.size();
                vector<int>c;
                for(int i=0;i<len;i++){
                    TreeNode *t = q.front();
                    q.pop();
                    c.push_back(t->val);
                    if(t->left) q.push(t->left);
                    if(t->right) q.push(t->right);
                }
                result.push_back(c);
            }
            return result;
        }

};

22.之字形打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
思路:在按行打印二叉树基础上添加一行reverse即可。


python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        if not pRoot :return []
        layers = [[pRoot,]]
        while layers[-1] != []:
            layer = []
            for root in layers[-1]:
                if root.left != None:
                    layer.append(root.left)
                if root.right != None:
                    layer.append(root.right)
            layers.append(layer)
        ret = []
        for i,layer in enumerate(layers[:-1]):
            layer_values = [root.val for root in layer]
            if i%2 == 1 :
                ret.append(layer_values[::-1])
            else:
                ret.append(layer_values)
        return ret

c++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int>>result;
            if(pRoot==NULL)return result;
            queue<TreeNode*>q;
            q.push(pRoot);
            bool rev=false;
            while(q.size()!=0){
                int len=q.size();
                vector<int>c;
                for(int i=0;i<len;i++){
                    TreeNode *t = q.front();
                    q.pop();
                    c.push_back(t->val);
                    if(t->left) q.push(t->left);
                    if(t->right) q.push(t->right);
                }
                if(rev)reverse(c.begin(),c.end());
                rev=!rev;
                result.push_back(c);
            }
            return result;
        }

};

23.序列化与反序列化二叉树

序列化即按照一定的遍历方式如前序、中序、后序、按层等,将二叉树转换为字符串。空节点以’#’方式保存。反序列化即按照序列化的遍历方式,将字符串重新转换为内存中树的形式。
思路:按照前序遍历方式,通过递归实现。


python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Serialize(self, root):
        # write code here
        def doit(node):
            if node:
                vals.append(str(node.val))
                doit(node.left)
                doit(node.right)
            else:
                vals.append('#')
        vals = []
        doit(root)
        return ' '.join(vals)

    def Deserialize(self, s):
        # write code here
        def doit():
            val = next(vals)
            if val == '#':
                return None
            node = TreeNode(int(val))
            node.left = doit()
            node.right = doit()
            return node
        vals = iter(s.split())
        return doit()

C++(存疑)

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
private:
    TreeNode* decode(char *&str) {
        if(*str=='#'){
            str++;
            return NULL;
        }
        int num = 0;
        while(*str != ',')
            num = num*10 + (*(str++)-'0');
        str++;
        TreeNode *root = new TreeNode(num);
        root->left = decode(str);
        root->right = decode(str);
        return root;
    }
public:
    char* Serialize(TreeNode *root) {   
        if(!root) return "#";
        string r = to_string(root->val);
        r.push_back(',');
        char *left = Serialize(root->left);
        char *right = Serialize(root->right);
        char *ret = new char[strlen(left) + strlen(right) + r.size()];
        strcpy(ret, r.c_str());
        strcat(ret, left);
        strcat(ret, right);
        return ret;
    }
    TreeNode* Deserialize(char *str) {
        return decode(str);
    }
};

24.数据流中的中位数

使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:注意python与c++中的成员变量的定义方式、sort函数的使用


python

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.data=[]
    def Insert(self, num):
        # write code here
        self.data.append(num)
        self.data.sort()
    def GetMedian(self,data):
        # write code here
        length=len(self.data)
        if length%2==0:
            return (self.data[length//2]+self.data[length//2-1])/2.0
        else:
            return self.data[int(length//2)]

c++

class Solution
{
    vector<int> number;
public:

    void Insert(int num)
    {
        number.push_back(num);
    }

    double GetMedian()
    {
        sort(number.begin(),number.end());
        if(number.size() % 2 == 1)
        {   
            return (double)(number[number.size()/2]);
        }
        else
        {
            return (double)((double)((number[(number.size()/2)-1])+(number[number.size()/2]))/2);
        }
    }

};

25.二叉搜索树的第k个节点

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路:考虑到二叉搜索树(BST)中,中序遍历的结果即有序数组。


python

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
#    def __ini__(self):
#        self.data=[]
    def KthNode(self, pRoot, k):
        # write code here
        if pRoot==None:
            return None
        global data
        data = []
        self.Traver(pRoot)
        if k>len(data) or k<=0:
            return None
        return data[k-1]
    def Traver(self, pRoot):
        if pRoot==None:
            return None
        self.Traver(pRoot.left)
        data.append(pRoot)
        self.Traver(pRoot.right)

c++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    TreeNode* KthNode(TreeNode* root, int k)
    {
        TreeNode *res = NULL;
        int c = 0;

        inorder(root, &res, k, &c);

        return res;
    }
    void inorder(TreeNode* root, TreeNode **res, int k, int *c)
    {
        if (root)
        {
            inorder(root -> left, res, k, c);
            ++*c;
            if (*c == k) *res = root;
            inorder(root -> right, res, k, c);
        }
    }

};

26.重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:采用递归,根据前序遍历中根节点位于首位,在中序遍历中找出,将前序遍历、中序遍历的左右子树序列递归处理。


python

class Solution(object):
    def reConstructBinaryTree(self, pre, tin):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if pre==[]:
            return None
        val = pre[0]
        idx = tin.index(val)
        ltin = tin[0:idx]
        rtin = tin[idx+1:]
        lpre = pre[1:1+len(ltin)]
        rpre = pre[1+len(ltin):]
        root = TreeNode(val)
        root.left = self.reConstructBinaryTree(lpre,ltin)
        root.right = self.reConstructBinaryTree(rpre,rtin)
        return root

C++

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        int veclen = pre.size();
        if (veclen==0)return NULL;
        vector<int>preleft,preright,vinleft,vinright;
        TreeNode* head=new TreeNode(pre[0]);
        int gen = 0;
        for(int i=0;i<veclen;i++){
            if(vin[i]==pre[0]){
                gen=i;
                break;
            }
        }
        for (int i = 0;i<gen;i++){
            vinleft.push_back(vin[i]);
            preleft.push_back(pre[i+1]);
        }
        for (int i = gen+1;i<veclen;i++){
            vinright.push_back(vin[i]);
            preright.push_back(pre[i]);
        }
        head->left=reConstructBinaryTree(preleft,vinleft);
        head->right=reConstructBinaryTree(preright,vinright);
        return head;
    }
};

27.滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。


python

# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if size == 0:
            return []
        ret = []
        stack = []
        for pos in range(len(num)):
            while (stack and stack[-1][0] < num[pos]):
                stack.pop()
            stack.append((num[pos], pos))
            if pos>=size-1:
                while(stack and stack[0][1]<=pos-size):
                    stack.pop(0)
                ret.append(stack[0][0])
        return ret

c++

class Solution {
public:
    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        vector<int>result;
        if((num.size()<1)||(size<1))return result;
        if(num.size()<size)return result;
        for (int i=0;i<(num.size()-size+1);i++){
            int m=num[i];
            for(int j=i+1;j<i+size;j++){
                if(num[j]>m)m=num[j];
            }
            result.push_back(m);
        }
        return result;
    }
};

28.用两个栈实现队列

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:注意c++的STL中的stack,top()和pop()的区别。


python

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1=[]
        self.stack2=[]
    def push(self, node):
        # write code here
        while(len(self.stack2)):
            self.stack1.append(self.stack2.pop());
        self.stack1.append(node)
    def pop(self):
        # return xx
        while(len(self.stack1)):
            self.stack2.append(self.stack1.pop());
        return self.stack2.pop()

c++

class Solution
{
public:
    void push(int node) {
        while(stack2.size()){
            stack1.push(stack2.top());
            stack2.pop();
        }
        stack1.push(node);
    }

    int pop() {
        while(stack1.size()){
            stack2.push(stack1.top());
            stack1.pop();}
        int temp=stack2.top();
        stack2.pop();
        return temp;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

29.旋转数组最小数字

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


python

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if len(rotateArray)==0:
            return 0
        result = rotateArray[0]
        for i in range(len(rotateArray)-1):
            if rotateArray[i]>rotateArray[i+1]:
                result=rotateArray[i+1]
                break
        return result

c++

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if (rotateArray.size()==0)return 0;
        int result=rotateArray[0];
        for(int i=0;i<rotateArray.size()-1;i++){
            if(rotateArray[i]>rotateArray[i+1]) {
                result=rotateArray[i+1];
                break;}
        }
        return result;
    }
};

30.丑数

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:若从1开始,每个数判断是否只有2,3,5三个质因数,则时间复杂度太高。因此考虑牺牲一部分空间,保存前K个丑数,则下一个丑数必定是前面某个丑数乘2或3或5所得,因此只需将现有丑数乘2、3、5后除去已有丑数,再选择最小数加入丑数list后对list排序即可。下述c++方法更加巧妙,有待深究。


python:

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if index<1:
            return 0
        result=[1,2,3,4,5]
        while(index>len(result)):
            result=self.addnum(result)
        return result[index-1]
    def addnum(self, result):
        a1=set([b*2 for b in result]+[b*3 for b in result]+[b*5 for b in result])
        a2=a1-set(result)
        a2=list(a2)
        a2.sort()
        result.append(a2[0])
        result.sort()
        return result

c++

class Solution {
public:
   int GetUglyNumber_Solution(int index) {
        if (index < 7)return index;
        vector<int> res(index);
        res[0] = 1;
        int t2 = 0, t3 = 0, t5 = 0, i;
        for (i = 1; i < index; ++i)
        {
            res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5));
            if (res[i] == res[t2] * 2)t2++;
            if (res[i] == res[t3] * 3)t3++;
            if (res[i] == res[t5] * 5)t5++;
        }
        return res[index - 1];
    }
};

31.两个链表的第一个公共节点

输入两个链表,找出它们的第一个公共结点。
思路:两个链表既然有公共部分,则必然从第一个公共节点往后全部相同,因此可以先求出两个链表长度,去掉较长节点的前面多余部分,此时相同长度,之后逐个遍历是否相同即可。


python

class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        if pHead1== None or pHead2 == None:
            return None
        pa = pHead1
        pb = pHead2 
        while(pa!=pb):
            pa = pHead2 if pa is None else pa.next
            pb = pHead1 if pb is None else pb.next
        return pa

c++

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if((pHead1==NULL)||(pHead2==NULL))return NULL;
        int len1=getlen(pHead1);
        int len2=getlen(pHead2);
        if(len1>len2){
            for(int i=0;i<len1-len2;i++)pHead1=pHead1->next;
        }
        else{
            for(int i=0;i<len2-len1;i++)pHead2=pHead2->next;}
        while(pHead1!=pHead2){
            pHead1=pHead1->next;
            pHead2=pHead2->next;
        }
        return pHead1;
    }
    int getlen(ListNode* pHead){
        int len=1;
        while(pHead->next){
            len++;
            pHead=pHead->next;
        }
        return len;
    }
};

32.第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
思路:记录出现次数,明显要用到hash,python中使用字典dict,c++中使用STL中的map。将出现的字符放入队列,最后pop第一个只出现的一次的字符。另外,通过本题熟悉对dict和map的使用。


python

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        queue = []
        memories = dict()
        for idx,char in enumerate(s):
            if char not in memories:
                queue.append(idx)
                memories[char]=0
            memories[char]+=1
            while(queue and memories[s[queue[0]]]>1):
                queue.pop(0)
        return queue[0] if queue else -1

c++

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        map<char, int> mp;
        for(int i = 0; i < str.size(); ++i)
            mp[str[i]]++;
        for(int i = 0; i < str.size(); ++i){
            if(mp[str[i]]==1)
                return i;
        }
        return -1;
    }
};

33.数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007。(size<=2*10^5)
思路:逆序对若是逐一对比,则复杂度为O(n2)。因此,考虑使用归并排序。每次归并时,放入右堆元素时左堆剩余元素数即此时逆序对数。


python

# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # write code here
        if not data:
            return 0
        temp = [i for i in data]
        return self.mergeSort(temp, data, 0, len(data)-1) % 1000000007

    def mergeSort(self, temp, data, low, high):
        if low >= high:
            temp[low] = data[low]
            return 0
        mid = (low + high) / 2
        left = self.mergeSort(data, temp, low, mid)
        right = self.mergeSort(data, temp, mid+1, high)

        count = 0
        i = low
        j = mid+1
        index = low
        while i <= mid and j <= high:
            if data[i] <= data[j]:
                temp[index] = data[i]
                i += 1
            else:
                temp[index] = data[j]
                count += mid-i+1
                j += 1
            index += 1
        while i <= mid:
            temp[index] = data[i]
            i += 1
            index += 1
        while j <= high:
            temp[index] = data[j]
            j += 1
            index += 1
        return count + left + right

C++

class Solution {
    long long count=0;
public:
    int InversePairs(vector<int> data) {
        if (data.size()<=1)return 0;
        MergeSort(data,0,data.size()-1);
        return count%1000000007;
    }
    void merge(vector<int>& nums, int l1, int r1, int l2, int r2 ) {
        int i = l1;int j = l2;
        int n = (r1 - l1 + 1) + (r2 - l2 + 1);
        vector<int> temp(n);
        int k = 0;
        while(i<=r1&&j<=r2){
            if(nums[i] < nums[j])
                temp[k++] = nums[i++];
            else{
                temp[k++] = nums[j++];
                count+=r1-i+1;}
        }
        while(i<=r1)
            temp[k++] = nums[i++];
        while(j<=r2)
            temp[k++] = nums[j++];
        for(int i = 0; i < n;i++)
            nums[l1 + i] = temp[i];
    }

    void MergeSort(vector<int>& nums,int start, int end) {
        if (start < end) {
            int mid = (start + end) >> 1;
            MergeSort(nums, start, mid);
            MergeSort(nums, mid + 1, end);
            merge(nums, start, mid, mid + 1, end);
        }
    }

};

34.最大连续子数列

计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:若暴力遍历,则需要O(n2)。可以考虑用分治法,以递归地方式将数列分为两部分,则最大连续子数列必存在于这两部分或者两部分都有这三种情况。或者使用动态规划,找到递推公式。应当注意,若全是负数,则最大子数列之和不是0。


python

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        LocalSum=0
        Sum=0
        minSum=array[0]
        for i in range(len(array)):
            LocalSum += array[i]
            if(array[i]>minSum):
                minSum=array[i]
            if(LocalSum>Sum):
                Sum=LocalSum
            elif(LocalSum<0):
                LocalSum=0
        if minSum<0:
            Sum=minSum
        return Sum

c++

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        int LocalSum=0,Sum=0,minSum=array[0];
        for (int i=0;i<array.size();i++){
            LocalSum+=array[i];
            if(array[i]>minSum)minSum=array[i];
            if(LocalSum>Sum)Sum=LocalSum;
            else if(LocalSum<0)LocalSum=0;
        }
        if(minSum<0)Sum=minSum;
        return Sum;

    }
};

另外,此题有一更好的解法

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {

        int cursum=array[0];
        int maxsum=array[0];
        for(int i=1;i<array.size();i++){
            cursum+=array[i];
            if(cursum<array[i])
                cursum=array[i];
            if(cursum>maxsum)
                maxsum=cursum;           
        }
    return maxsum;
    }
};

35.最小的k个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路:本题旨在分析各种排序算法的原理,复杂度计算。选取最小的k个,因此不需要全部排序。堆排序时间复杂度O(nlogk),冒泡排序复杂度O(nk),快速排序O(nlogn)。


python

# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        if not tinput:
            return []
        if k>len(tinput):
            return []
        tinput.sort()
        return tinput[:k]

c++

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {


        vector<int> v;
        if(k>input.size())
            return v;
        sort(input.begin(),input.end());
        for(int i=0;i<k;i++)
            v.push_back(input[i]);
        return v;
    }
};

36.数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路:排序后,从中间位置向两边计数,直到不等于中间位置数值,看是否超过长度一半。


python

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        if not numbers:
            return 0
        numbers.sort()
        mid=len(numbers)//2
        times=1
        if(mid-1>0):
            for i in range(mid-1):
                if numbers[mid-2-i]==numbers[mid-1]:
                    times+=1
                else:
                    break
        if(mid<len(numbers)):
            for i in range(len(numbers)-mid):
                if numbers[mid+i]==numbers[mid-1]:
                    times+=1
                else:
                    break
        if times>mid:
            return numbers[mid-1]
        else:
            return 0

c++

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int length = numbers.size();
        if (length == 0)
            return 0;
        sort(numbers.begin(), numbers.end());
        int max_num = 0;
        int num = 0;
        int val = numbers[0];
        for (int i = 0; i < length; i++) {
            if (val == numbers[i]) {
                num++;
            }
            else {
                max_num = num > max_num ? num : max_num;
                if (max_num > length / 2)
                    return val;
                val = numbers[i];
                num = 1;
            }
        }
        max_num = num > max_num ? num : max_num;
        if (max_num > length / 2)
            return val;
        else
            return 0;
    }
};

37.整数中1出现的次数

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路:单独分析1到n中每一位中出现1的次数。对于某一位数字k,若k等于0,则此位含1的次数为更高位数字乘当前位数;若k等于1,则此位含1的次数为更高位数字乘当前位数+低位数字+1;若k等于2~9,则此位含1的次数为(更高位数字+1)乘当前位数。


python

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        res=0
        tmp=n
        base=1
        while tmp:
            last=tmp%10
            tmp=tmp/10
            res+=tmp*base
            if last==1:
                res+=n%base+1
            elif last>1:
                res+=base
            base*=10
        return res

c++

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        int i=1;
        int count=0;
        while(n/i!=0){

            int high=n/(i*10);
            int low=n-(n/i)*i;
            int now=(n/i)%10;
            if (now==0){
                count+=high*i;
            }
            else if(now==1){
                count+=high*i+low+1;
            }
            else{
                count+=(high+1)*i;
            }
            i*=10;
        }
        return count;
    }
};

38.把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:并不是a小于b那么ab小于ba,因为3,31拼成331大于313,所以我们应该设置自己的一套比较规则,如果ab小于ba那么称为a小于b,所以我们需要做的是把整个数组按照我们的比较规则从小到大排列。然后从头到尾用字符串的形式串起来。此题要格外注意。


python

# -*- coding:utf-8 -*-
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        if not numbers:
            return ""
        lmb = lambda n1, n2:int(str(n1)+str(n2))-int(str(n2)+str(n1))
        array = sorted(numbers, cmp=lmb)
        return ''.join([str(i) for i in array])

c++

class Solution {
public:
    string PrintMinNumber(vector<int> numbers) {
        int len = numbers.size();
        if(len == 0) return "";
        sort(numbers.begin(), numbers.end(), cmp);
        string res;
        for(int i = 0; i < len; i++){
            res += to_string(numbers[i]);
        }
        return res;
    }
    static bool cmp(int a, int b){
        string A = to_string(a) + to_string(b);
        string B = to_string(b) + to_string(a);
        return A < B;
    }
};

39.数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路:(1)本题可使用hash。(2)考虑到数组中数字范围固定,因此可以利用固定长度n的bool或int类型的数组,遍历原数组,每当出现一个数组a[i]则将新数组中b[a[i]]变换,到遍历到有变化的数字时即重复。(3)另外还有最高效的方法,不需要额外空间,从头遍历数组,若a[i]等于i,则i++;否则判断a[i]是否等于a[a[i]],若相等则返回True,否则互换两值,继续进行直到a[i]等于i。需要注意的是,互换a[i]和a[a[i]]时,赋值后a[i]已变,故用a[temp]表示而非a[a[i]]。


python

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        if len(numbers)==0:
            return False
        for i in range(len(numbers)):
            while(numbers[i]!=i):
                if(numbers[numbers[i]]==numbers[i]):
                    duplication[0]=numbers[i]
                    return True
                else:
                    temp=numbers[i]
                    numbers[i]=numbers[temp]
                    numbers[temp]=temp
        return False

c++

class Solution {
public:
    // Parameters:
    //        numbers:     an array of integers
    //        length:      the length of array numbers
    //        duplication: (Output) the duplicated number in the array number
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    bool duplicate(int numbers[], int length, int* duplication) {
        if(numbers == NULL || length <= 0) {
            return false;
        }

        for(int i = 0; i < length; i++) {
            while(numbers[i] != i) {
                if(numbers[i] == numbers[numbers[i]]) {
                    duplication[0] = numbers[i];
                    return true;
                }
                int temp = numbers[i];
                numbers[i] = numbers[temp];
                numbers[temp] = temp;
            }
        }

        return false;
    }
};

40.构建乘积数组

给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]A[i-1]*A[i+1]…*A[n-1]。不能使用除法。
思路:本题若直接逐个计算的话,需要循环套循环,O(n2)的复杂度。若将其看作n乘n的矩阵,A和B分别为两边,则可通过对角线将矩阵分为上下三角。对于下三角而言,B[0]=1,B[1]=B[0]*A[0]……上三角同理。此时仅需O(n)的时间消耗。


python

# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        # write code here
        if not A:
            return []
        # 计算前面一部分
        num = len(A)
        B = [None] * num
        B[0] = 1
        for i in range(1, num):
            B[i] = B[i-1] * A[i-1]
        # 计算后面一部分
        # 自下而上
        # 保留上次的计算结果乘本轮新的数,因为只是后半部分进行累加,所以设置一个tmp,能够保留上次结果
        tmp = 1
        for i in range(num-2, -1, -1):
            tmp *= A[i+1]   
            B[i] *= tmp
        return B

c++

class Solution {
public:
    vector<int> multiply(const vector<int>& A) {
        vector<int>B(A.size());
        int temp =1;
        for (int i=0;i<A.size();i++){
            B[i]=temp;
            temp*=A[i];
        }
        temp=1;
        for(int i=A.size()-1;i>=0;i--){
            B[i]*=temp;
            temp*=A[i];
        }
        return B;
    }
};

41.二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:从左到右递增,从上到下递增,因此若从左上角开始找,每次面对向下和向右两条增大的路径,因此选择从左下角开始找,若偏大则向上走,若偏小则向右走。另一种思路是逐行使用二分查找。


# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        rows = len(array) - 1
        cols= len(array[0]) - 1
        i = rows
        j = 0
        while j<=cols and i>=0:
            if target<array[i][j]:
                i -= 1
            elif target>array[i][j]:
                j += 1
            else:
                return True
        return False

c++

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int rows = array.size();
        int cols = array[0].size();
        int i=rows-1,j=0;
        while(i>=0 && j<cols){
            if(target<array[i][j])
                i--;
            else if(target>array[i][j])
                j++;
            else
                return true;
        }
        return false;
    }
};

42.扑克牌顺子

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
思路:要想满足顺子,首先不能够有除大小王外重复的牌。需要把大小王作为万能牌填充,因此大小王的数量应大于除大小王外其他牌最大减最小。


python

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if not numbers:
            return 0
        numbers.sort()
        zeros = numbers.count(0)
        for i, v in enumerate(numbers[:-1]):
            if v!=0:
                if numbers[i+1]==v:
                    return False
                zeros -= (numbers[i+1]-numbers[i]-1)
                if zeros<0:
                    return False
        return True

c++

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size()==0)return false;
        int count[14]={0};
        int min=14;
        int max=-1;
        for(int i=0;i<numbers.size();i++){
            if(numbers[i]==0)continue;
            else{
                if (count[numbers[i]]!=0)return false;
                else count[numbers[i]]++;
                if (min>numbers[i])min=numbers[i];
                if (max<numbers[i])max=numbers[i];
            }
        }
        if(max-min>=5)return false;
        else return true;
    }
};

43.孩子们的游戏

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
思路:此题为经典的约瑟夫环。若是无脑求解,可以用环形链表逐次删除节点。但若想递归求解,则需要分析问题,对于每次n个人报数,其点到的人的位置与剩下的n-1个人中点到的人的位置有关,因此可以写出递归式,详见博客


python

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        if n < 1 or m < 1:
            return -1
        last = 0 #n=1
        for i in range(2, n + 1):
            last = (last + m ) % i
        return last

c++

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if(n==0) return -1;
        int s=0;
        for(int i=2;i<=n;i++){
            s=(s+m)%i;
        }
        return s;
    }
};

44.正则表达式匹配

请实现一个函数用来匹配包括’.’和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’‘表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab*ac*a”匹配,但是与”aa.a”和”ab*a”均不匹配。
思路:采用递归,分情况讨论。
python

# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if (len(s) == 0 and len(pattern) == 0):
            return True
        if (len(s) > 0 and len(pattern) == 0):
            return False
        if (len(pattern) > 1 and pattern[1] == '*'):
            if (len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.')):
                return (self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern))
            else:
                return self.match(s, pattern[2:])
        if (len(s) > 0 and (pattern[0] == '.' or pattern[0] == s[0])):
            return self.match(s[1:], pattern[1:])
        return False

c++

class Solution {
public:
    bool match(char* str, char* pattern)
    {
        if (pattern[0] == 0 && str[0] == 0){
            return true;
        }
        if (pattern[0] != 0 && pattern[1] == '*'){
            if (match(str, pattern + 2))
                return true;
        }
        if ((pattern[0] == '.' && str[0]) || str[0] == pattern[0]){
            if (match(str + 1, pattern + 1))
                return true;
            if (pattern[1] == '*' && match(str + 1, pattern)){
                return true;
            }
        }
        return false;
    }
};

45.表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。
思路:按照至多只有一个e或E,e前后各至多只能一个正负符号,e后无小数点,后面的正负号紧跟e后面等。本题关键是理清逻辑。另外,注意else if与多个if的区别,else if只要满足一个,后面的else if便不再判断。


python

# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        hasE=False;sign=False;decimal=False;
        for i in range(len(s)):
            if s[i]=='e' or s[i]== 'E':
                if i==len(s)-1:
                    return False
                if hasE:
                    return False
                hasE=True
            elif s[i]=='+' or s[i]=='-':
                if sign and s[i-1]!='e' and s[i-1]!='E':
                    return False
                if (not sign) and i>0 and s[i-1]!='e' and s[i-1]!='E':
                    return False
                sign = True
            elif s[i]=='.':
                if decimal or hasE:
                    return False
                decimal = True
            elif s[i]<'0' or s[i]>'9':
                return False
        return True

c++

class Solution {
public:
    bool isNumeric(char* str) {
        bool sign = false, decimal = false, hasE = false;
        for (int i = 0; i < strlen(str); i++) {
            if (str[i] == 'e' || str[i] == 'E') {
                if (i == strlen(str)-1) return false; 
                if (hasE) return false;
                hasE = true;
            } 
            else if (str[i] == '+' || str[i] == '-') {
                if (sign && str[i-1] != 'e' && str[i-1] != 'E') return false;
                if (!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E') return false;
                sign = true;
            } 
            else if (str[i] == '.') {
                if (hasE || decimal) return false;
                decimal = true;
            } 
            else if (str[i] < '0' || str[i] > '9')
                return false;
        }
        return true;
    }
};

46.字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。如果当前字符流没有存在出现一次的字符,返回#字符。
思路:使用队列和hash,即c++中的map和python中的dict,注意语法。另外,c++的queue中,push而非push_back,pop并没有返回值,需要用a.front()。
python

# -*- coding:utf-8 -*-
class Solution:
    # 返回对应char
    def __init__(self):
        self.letter=dict()
        self.queue=[]
    def FirstAppearingOnce(self):
        # write code here
        while len(self.queue) and self.letter[self.queue[0]]>1:
            self.queue.pop(0)
        return self.queue[0] if len(self.queue) else '#'
    def Insert(self, char):
        # write code here
        if char not in self.letter:
            self.letter[char]=0
        self.letter[char]+=1
        if self.letter[char]==1:
            self.queue.append(char)

c++

class Solution
{
    map<char,int>letter;
    queue<char>myqueue;
public:
  //Insert one char from stringstream
    void Insert(char ch)
    {
        letter[ch]++;
        if (letter[ch]==1){
            myqueue.push(ch);
        }
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        while((myqueue.size()!=0)&&(letter[myqueue.front()]!=1)){
            myqueue.pop();}
        if(myqueue.size()!=0)return myqueue.front();

        return'#';
    }

};

47.替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:注意在c++中,空格本身占一个char的位置,替换成”%20”后占三个char,因此指针需要延后。所以选择将变换后的内容保存在新的vector中,完全处理后再拷贝至原首位置。


python

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def __init__(self):
        self.other=[]
    def replaceSpace(self, s):
        # write code here
        for lett in s:
            if lett==' ':
                self.other+="%20"
            else:
                self.other.append(lett)
        return ''.join(self.other)

c++

class Solution {
vector<char>other;
int count=0;
public:
    void replaceSpace(char *str,int length) {
        char *str1=str;
        for (int i=0;i<length;i++){
            if (*str==' ') {
                other.push_back('%');
                other.push_back('2');
                other.push_back('0');
                count+=3;
            }
            else{
                other.push_back(*str);
                count+=1;
            }
            str++;
        }
        for(int j=0;j<count;j++){
            *str1=other[j];
            str1++;
        }
    }
};

48.矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路:采用深度优先搜索,递归进行。


python

# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        # write code here
        for i in range(rows):
            for j in range(cols):
                if matrix[i*cols+j] == path[0]:
                    if self.find(list(matrix),rows,cols,path[1:],i,j):
                        return True
        return False
    def find(self,matrix,rows,cols,path,i,j):
        if not path:
            return True
        matrix[i*cols+j]='0'
        if j+1<cols and matrix[i*cols+j+1]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i,j+1)
        elif j-1>=0 and matrix[i*cols+j-1]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i,j-1)
        elif i+1<rows and matrix[(i+1)*cols+j]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i+1,j)
        elif i-1>=0 and matrix[(i-1)*cols+j]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i-1,j)
        else:
            return False

49.机器人的运动范围

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:同样是DFS。


python

# -*- coding:utf-8 -*-
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        board = [[0 for _ in range(cols)] for _ in range(rows)]
        def block(r,c):
            s = sum(map(int,str(r)+str(c)))
            return s>threshold
        class Context:
            acc = 0
        def traverse(r,c):
            if not (0<=r<rows and 0<=c<cols): return
            if board[r][c]!=0: return
            if board[r][c]==-1 or block(r,c):
                board[r][c]=-1
                return
            board[r][c] = 1
            Context.acc+=1
            traverse(r+1,c)
            traverse(r-1,c)
            traverse(r,c+1)
            traverse(r,c-1)
        traverse(0,0)
        return Context.acc

50.1+2+3+…+n

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
思路:不能使用一系列条件语句,则考虑其他方法终止迭代或循环。考虑短路特性,即多个条件and中,若前面出现false,则终止,不再进行后面的。


python

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.sum = 0
    def Sum_Solution(self, n):
        # write code here
        def qiusum(n):
            self.sum += n
            n -= 1
            return n>0 and self.Sum_Solution(n)

        qiusum(n)
        return self.sum

51.不用加减乘除做加法

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
思路:不能使用加减乘除四则运算,则考虑使用位运算。在数字电路基础中学过加法运算,当前位为两数该位异或运算,向下一位进位为当前位与运算。循环进行直到进位为0。本题用python一直超时。


c++

class Solution {
public:
    int Add(int num1, int num2)
    {
        int re1=num1^num2;
        int re2=num1&num2;
        while(re2){
            int temp1=re1;
            int temp2=re2<<1;
            re1=temp1^temp2;
            re2=temp1&temp2;
        }
        return re1;

    }
};

52.二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:二叉搜索树按照中序遍历即有序数组,因此递归进行处理,将左子树的最右端节点的right指向root,root的left指向左子树最右端节点,右子树同理。注意判断是否为NULL即可。


c++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree==NULL)
            return NULL;
        if(pRootOfTree->left==NULL&&pRootOfTree->right==NULL)
            return pRootOfTree;
        TreeNode* left = Convert(pRootOfTree->left);
        TreeNode* curr = left;
        while(curr!=NULL&&curr->right!=NULL)
            curr=curr->right;
        if(curr!=NULL)
        {
            curr->right=pRootOfTree;
            pRootOfTree->left = curr;
        }
        TreeNode* right = Convert(pRootOfTree->right);
        if(right!=NULL)
        {
            pRootOfTree->right = right;
            right->left = pRootOfTree;
        }
        return left!=NULL?left:pRootOfTree;
    }
};

猜你喜欢

转载自blog.csdn.net/Lyteins/article/details/81843061