剑指offer(21-40题)

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

void reOrderArray(vector<int> &array) {
        int n = array.size();
        int left = 0, right = n-1;
        while(left < right){
            while(left< right){
                if((array[left]&1)==1)
                    left++;
                else
                   break;
            }
            while(right > left){
                if((array[right]&1) ==0)
                    right--;
                else 
                    break;
            }
          if(left < right){
              int tmp = array[right];
              array[right]= array[left];
              array[left] = tmp;
              left++;
              right--;
          }  
        }
    }

牛客网的题目有另一个约束:奇数和奇数,偶数和偶数之间的相对位置不变
https://www.nowcoder.com/practice/beb5aa231adc45b2a5dcc5b62c93f593?tpId=13&tqId=11166&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

P134
链表中倒数第k个节点
此题要考虑清楚各种情况,代码的鲁棒性要强

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if( pListHead == NULL || k == 0) return NULL;   // k==0 要注意
        ListNode * quickPoint = pListHead;
        for(int i=0; i< k-1; i++){
            quickPoint = quickPoint->next;
            if(quickPoint == NULL) return NULL;
        }
        ListNode * slowPoint = pListHead;
        while(quickPoint->next){
            slowPoint = slowPoint->next;
            quickPoint = quickPoint->next;
        }
        return slowPoint;
    }

P139
链表中环的入口节点

 ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
         if(pHead == NULL) return NULL;
         ListNode * quickPoint = pHead->next, * slowPoint = pHead->next;
         if(slowPoint==NULL) return NULL;
         quickPoint = quickPoint->next;
         if(quickPoint==NULL) return NULL;
        while(slowPoint!=quickPoint){
            slowPoint = slowPoint->next;
            quickPoint = quickPoint->next;
            if(quickPoint==NULL) return NULL;
            quickPoint = quickPoint->next;
            if(quickPoint==NULL) return NULL;   
        }
        
        
           ListNode * meet = slowPoint;
           slowPoint = slowPoint->next;
           int cnt = 1;
           while(slowPoint != meet){
               cnt++;
               slowPoint = slowPoint->next;
           }
           quickPoint = pHead;
           slowPoint = pHead;
           while(cnt){
               quickPoint = quickPoint->next;
               cnt--;
           }
           while(slowPoint != quickPoint){
               slowPoint = slowPoint->next;
               quickPoint = quickPoint->next;
           }
           return slowPoint; 
          
    }
ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
         if(pHead == NULL) return NULL;
         ListNode * quickPoint = pHead->next, * slowPoint = pHead->next;
         if(slowPoint==NULL) return NULL;
         quickPoint = quickPoint->next;
     
        while(quickPoint){
            if(quickPoint == slowPoint) break;
            slowPoint = slowPoint->next;
            quickPoint = quickPoint->next;
            if(quickPoint==NULL) return NULL;
            quickPoint = quickPoint->next;  
        }
      
           ListNode * meet = slowPoint;
           slowPoint = slowPoint->next;
           int cnt = 1;
           while(slowPoint != meet){
               cnt++;
               slowPoint = slowPoint->next;
           }
           quickPoint = pHead;
           slowPoint = pHead;
           while(cnt){
               quickPoint = quickPoint->next;
               cnt--;
           }
           while(slowPoint != quickPoint){
               slowPoint = slowPoint->next;
               quickPoint = quickPoint->next;
           }
           return slowPoint; 
          
    }

P142
反转链表

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

P145
合并两个排序的链表

 ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if( pHead1 == NULL ) return pHead2;
        if(pHead2 == NULL) return pHead1;
        ListNode * emptyNode  = new ListNode(0);
        ListNode * pre = emptyNode;
        ListNode * cur = NULL, * cur1 = pHead1, * cur2 = pHead2;
        while(cur1 != NULL && cur2 != NULL){
            if(cur1->val < cur2->val) {
                cur = cur1;
                cur1 = cur1->next;
            }else {
                cur = cur2;
                cur2 = cur2->next;
            }
             pre->next = cur;
             pre = cur;
        }
        if( cur1 ){
            pre->next = cur1;
        }
        if(cur2 ){
            pre->next = cur2;
        }
        return emptyNode->next;
    }

递归方法

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

P148
树的子结构
对自己来说,难度有点大

class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
         bool result = false;
         if(pRoot1!=NULL && pRoot2!=NULL){
             if( abs(pRoot1->val - pRoot2->val)<1e-6){
                 result = isRight(pRoot1, pRoot2);
             }
             if(!result){
                 result = HasSubtree(pRoot1->left, pRoot2);
             }
             if(!result){
                 result = HasSubtree(pRoot1->right, pRoot2);
             }          
         }
         return result;
    }
 private:
    bool isRight(TreeNode * pRoot1, TreeNode * pRoot2){
         if(pRoot2 == NULL) return true;
         if(pRoot1 == NULL) return false;
         if( abs(pRoot1->val - pRoot2->val)<1e-6 ){
             return isRight(pRoot1->left, pRoot2->left) && isRight(pRoot1->right, pRoot2->right);
         }else 
             return false;
    }
};

P157
二叉树的镜像

class Solution {
public:
    void Mirror(TreeNode *pRoot) {
         if(pRoot == NULL) return ;
         TreeNode * tmp = pRoot->left;
         pRoot->left = pRoot->right;
         pRoot->right = tmp;
         Mirror(pRoot->left);
         Mirror(pRoot->right);
    }
};

非递归

void Mirror(TreeNode *pRoot) {
         if(pRoot == NULL) return ;
         queue<TreeNode *> q;
         q.push(pRoot);
         TreeNode * tmp = NULL;
         while(q.size()){
             tmp = q.front();
             q.pop();
             swap(tmp->left, tmp->right);
             if(tmp->left) q.push(tmp->left);
             if(tmp->right) q.push(tmp->right);
         }
         
    }

P159
对称的二叉树
对自己来说,有点难度

class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
         return isRight(pRoot, pRoot);
    }
private:
    bool isRight(TreeNode * r1, TreeNode * r2){
        if(r1 == NULL && r2 == NULL ) return true;
        if(r1 == NULL  ||  r2==NULL) return false;
        if( r1->val!= r2->val ) return false;
        return isRight(r1->left, r2->right) && isRight(r1->right, r2->left); 
    }
};

P161
顺时针打印矩阵
https://www.nowcoder.com/profile/6606749/codeBookDetail?submissionId=15814779

vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int> res;
        int row = matrix.size();
        if(row == 0) return res;
        int col = matrix[0].size();
        vector<vector<int>> flag(row, vector<int>(col,0));
        int i=0, j=0;
        int all = row*col;
        int cnt=0;
        while(cnt<all){
            while(j<col && flag[i][j]==0){
                res.push_back(matrix[i][j]);
                flag[i][j]=1;
                cnt++;
                j++;
            }
            j--;
            i++;
            while(i<row && flag[i][j]==0){
                res.push_back(matrix[i][j]);
                flag[i][j]=1;
                cnt++;
                i++;
            }
            i--;
            j--;
            while(j>=0 && flag[i][j]==0){
                res.push_back(matrix[i][j]);
                flag[i][j]=1;
                cnt++;
                j--;
            }
            j++;
            i--;
            while(i>=0 && flag[i][j]==0){
                res.push_back(matrix[i][j]);
                flag[i][j]=1;
                cnt++;
                i--;
            }
           i++; 
           j++;
        }
        return res;
    }
class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
         vector<int> res;
         int row = matrix.size();
         if(row ==0 )return res;
         int col = matrix[0].size();
         if(col ==0) return res;
         int left=0, right=col-1, top=0, bottom= row-1;
         while(left<=right && top<=bottom){
            for(int i=left;i<=right;i++){
                res.push_back(matrix[top][i]);
            }
            for(int i=top+1; i<= bottom;i++){
                res.push_back(matrix[i][right]);
            }
            if(top < bottom){
            for(int i= right-1; i>=left;i--)
                res.push_back(matrix[bottom][i]);
            }
            if(left < right){
            for(int i= bottom-1; i>top;i--)
                res.push_back(matrix[i][left]);
            }
            left++;
            top++;
            right--;
            bottom--;
              
         }
        return res;
    }
};

P165
包含min函数的栈

class Solution {
public:
    void push(int value) {
       s.push(value);
       if( minStack.empty()) minStack.push(value);
       else if( minStack.top() < value)
           minStack.push(minStack.top());
       else 
           minStack.push(value);
    }
    void pop() {
       if(!s.empty()){
       s.pop();
       minStack.pop();
       }
    }
    int top() {              // 个人觉得在top时也要判断是否空,但是无法在牛客上ac
       return s.top();
    }
    int min() {
        return minStack.top();
    }
private:
    stack<int> s;
    stack<int> minStack;
};

P168
栈的压入、弹出序列
https://www.nowcoder.com/profile/8709341/codeBookDetail?submissionId=17099336

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        int len1 = pushV.size(), len2 = popV.size();
        int start = 0;
        for(int i=0; i< len2; i++){
            if(!s.empty() && s.top()== popV[i])
                s.pop();
            else{
                while(start<len1 && pushV[start]!=popV[i]){
                    s.push(pushV[start]);
                    start++;
                }
                if( start >= len1) return false;
                else 
                    start++;
            }
        }
        if(s.empty())
        return true;
        else return false;
    }
private:
    stack<int> s;
};

P171
从上到下打印二叉树
以下代码是不分行打印二叉树

vector<int> PrintFromTopToBottom(TreeNode* root) {
          vector<int> res;
          if(root == NULL) return res;
          queue<TreeNode *> q;
          q.push(root);
          TreeNode * tmp= NULL;
          while(!q.empty()){
              tmp = q.front();
              q.pop();
              res.push_back(tmp->val);
              if(tmp->left) q.push(tmp->left);
              if(tmp->right) q.push(tmp->right);
          }
        return res;
    }

以下代码是分行打印二叉树

 vector<vector<int> > Print(TreeNode* pRoot) {
           vector<vector<int>> res;
           if(!pRoot) return res;
           queue<TreeNode *> q;
           q.push(pRoot);
           TreeNode * tmp = NULL;
           int k = 0;
           while(!q.empty()){
               k = q.size();
               vector<int> v;
               for(int i=0; i< k; i++){
                   tmp = q.front();
                   q.pop();
                   v.push_back(tmp->val);
                   if(tmp->left) q.push(tmp->left);
                   if(tmp->right) q.push(tmp->right);
               }
               res.push_back(v);
           }
           return res;
        }

之字形打印二叉树
方法一:仍用队列

 vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> res;
        if(!pRoot) return res;
        queue<TreeNode *> q;
        q.push(pRoot);
        int k = 0;
        TreeNode * tmp = NULL;
        int flag=0;
        while(!q.empty()){
            flag = 1- flag;
            k = q.size();
            vector<int> v;
            for(int i=0;i<k;i++){
               tmp = q.front();
               q.pop();
               v.push_back(tmp->val);
               if(tmp->left) q.push(tmp->left);
               if(tmp->right) q.push(tmp->right);
            }
            if(flag) res.push_back(v);
            else{
                reverse(v.begin(),v.end());
                res.push_back(v);
            }
        }
        return res;
    }
    

方法二:使用两个栈

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
       vector<vector<int>> res;
       if(!pRoot) return res;
       s1.push(pRoot);
       TreeNode * tmp = NULL;
       while(!s1.empty() || !s2.empty()){
           vector<int> v;
           if(!s1.empty()){
               while(!s1.empty()){
                  tmp = s1.top();
                  s1.pop();
                  v.push_back(tmp->val);
                  if(tmp->left) s2.push(tmp->left);
                  if(tmp->right) s2.push(tmp->right);        
               }
           }else{
                while(!s2.empty()){
                  tmp = s2.top();
                  s2.pop();
                  v.push_back(tmp->val);
                  if(tmp->right) s1.push(tmp->right);
                  if(tmp->left) s1.push(tmp->left);                 
               }
           }
           res.push_back(v);
       }
       return res;
    }
 private:
    stack<TreeNode *> s1;
    stack<TreeNode *> s2;
};

P180
二叉搜索树的后序遍历序列
此题,对我还是有点难度

class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {
         int n = sequence.size();
         if(n==1) return true;
         if(n==0) return false;
         return rec(sequence, 0, n-1);
        
    }
    bool rec(vector<int> & sequence, int start, int end){
         if(start >= end) return true;
         int root = sequence[end];
         int k=start;
         while(k < end ){
             if(sequence[k] > root)
                 break;
             k++;
         }  
        for(int i=k; i< end; i++){
            if(sequence[i]<root)
                return false;
        }      
        return rec(sequence, start, k-1) && rec(sequence, k, end-1 ); 
    }
};

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

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int>> res;
        if(!root) return res;
        vector<int> v;
        rec(root, expectNumber, res, v);
        return res;
    }
private:
    void rec( TreeNode * root, int num, vector<vector<int>> & res, vector<int> & v){
        v.push_back(root->val);
        num = num - root->val;
        if(root->left==NULL && root->right==NULL && num==0 ) {
            res.push_back(v);           
        }
        if(root->left){
            rec(root->left, num, res, v);
        }
        if(root->right){
            rec(root->right, num, res,v);
        }   
        v.pop_back();   
    }
};

P187
复杂链表的复制
此题值得思考的点还是挺多的,书中指明了三种方法。

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {   if(pHead == NULL) return NULL;
        // step 1: 复制节点
        RandomListNode * cur = pHead;
        RandomListNode * tmp = NULL;
        while(cur){
            RandomListNode * newNode = new RandomListNode(cur->label);
            tmp = cur->next;
            cur->next = newNode;
            newNode->next = tmp;
            cur = tmp;          
        }
        
        // step 2: 连接兄弟节点
        cur = pHead;
        while(cur){
            if(cur->random){
                cur->next->random = cur->random->next;
            }
            cur = cur->next->next;
        }
        
        // step 3: 拆分链表
        cur = pHead;
        RandomListNode * res = cur->next;
        while(cur){
            tmp = cur->next;
            cur->next = tmp->next;
            if(cur->next == NULL) break;       // 这一行要注意加上
            tmp->next = cur->next->next;
            cur = cur->next;    
        }
     return res;
    }
};

P191
二叉搜索树与双向链表
对二叉搜索树中序遍历得到的结果就是从小到大
还是对递归掌握不好

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree == NULL) return NULL;
        TreeNode * pre = NULL;
        inOrder(pRootOfTree, pre);
        while(pre->left)
            pre = pre->left;
        return pre;
    }
    void inOrder( TreeNode * cur, TreeNode * & pre){
        if(cur == NULL) return ;
        inOrder(cur->left, pre);
        cur->left = pre;
        if(pre) pre->right = cur;
        pre = cur;
        inOrder(cur->right, pre);
    }
};

P195
序列化二叉树
https://blog.csdn.net/u011475210/article/details/78889876
个人更倾向字符串的方法,因为树的val的值可正可负

class Solution {
public:
    // 本质上就是树的先根遍历
    void serializeHelper(TreeNode * cur, string & s){
        if(cur==NULL) {
            s += "$,";
            return ;
        }else{
            s += to_string(cur->val);
            s += ",";
            serializeHelper(cur->left,s);
            serializeHelper(cur->right,s);
        }
    }
    char* Serialize(TreeNode *root) {    
        if(!root) return NULL;
        string s = "";
        serializeHelper(root, s);
        char * res = new char[s.length()+1];
        strcpy(res, s.c_str());
        return res;
    }
    TreeNode * deserializeHelper(string & s){
     
         if(s[0]=='$'){
            s = s.substr(2);
            return NULL;
        }
        TreeNode * res = new TreeNode(stoi(s));
        s = s.substr(s.find_first_of(',')+1);
        res->left = deserializeHelper(s);
        res->right = deserializeHelper(s);
        return res;
    }
    TreeNode* Deserialize(char *str) {
        if(!str) return NULL;
        string s = str;
        return deserializeHelper(s);
    }
};

P197
字符串的排列
下面的连接很好,里面是多个排列题目
https://blog.csdn.net/sinat_33442459/article/details/73732486
牛客网要求按字典序打印,下面通过set做到,同时也考虑了字符可能重复。

class Solution {
public:
    vector<string> permutation;
    set<string> permutationSet;
    void p(string s, int index, int n){
        if(index == n-1) {
            permutationSet.insert(s);
            return ;
        }
        p(s, index+1,n);
        for(int i = index; i < n ;i++){
            if(s[i]!=s[index]){
            char tmp = s[index];
            s[index] = s[i];
            s[i] = tmp;
            p(s, index+1, n);
            tmp = s[index];
            s[index] = s[i];
            s[i] = tmp;
            }
        }       
    }
    vector<string> Permutation(string str) {
        if(str.length()==0) return permutation;
        int n = str.length();
        p(str, 0, n);
        for(set<string> :: iterator iter = permutationSet.begin(); iter != permutationSet.end(); ++iter ){
            permutation.push_back(*iter);
        }
        return permutation;
    }
};

P205
数组中出现次数超过一半的数字
这个题很重要
https://blog.csdn.net/liangzhaoyang1/article/details/51049237

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        map<int,int> m;
        int n = numbers.size();
        for(int i=0;i<n;i++)
            m[numbers[i]]++;
        map<int,int>::iterator iter = m.begin();
        while(iter!=m.end()){
            if(iter->second > n/2)
                return iter->first;
            iter++;
        }
        return 0;
    }
};

利用了partition
https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

class Solution {
public:
    void partition(vector<int> & numbers, int  target, int start, int end){
        if(start>=end) return;
        int val;
        int left = start, right =end;
        val = numbers[left];
        while(left<right){       
            while(right>left && numbers[right]>=val)
                right--;
            if(right > left){
            numbers[left] = numbers[right];
            left++;
            }
            while(left<right && numbers[left]<val)
                left++;
            if(left < right){
            numbers[right] = numbers[left];
            right--;
            }
        }
        numbers[left] = val;
        if(left == target/2) return;
        else if( target/2 > left) 
        partition(numbers, target, left+1,end );
        else 
        partition(numbers, target, start, left-1);       
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int n = numbers.size();
        if(n==0) return 0;
        int index = n/2;
        partition(numbers, index,0,n-1);
        int val = numbers[index];
        int cnt = 0;
        for(int i=0;i<n;i++){
            if(numbers[i]==val)
                cnt++;
        }
        if(cnt>index)
            return val;
        else 
            return 0;
    }
};

P209
最小的k个数
方法一:
时间复杂度O(n log n), 同时原数组也进行了改动

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        int n = input.size();
        if(n<k || k<=0) return res;
        sort(input.begin(), input.end());
        for(int i=0;i<k;i++)
            res.push_back(input[i]);
        return res;
    }
};

方法二:
时间复杂度O(n), 用上一题“数组中出现次数超过一半的数字”的方法,基于partition函数定位到第k大的数字,那么位于左边的就是我们要的结果,注意:得到的这k个数字不一定有序
此外,此方法也修改了输入的数组
可见,快排的思想还是很重要的,很多地方都有用到

	
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        int n = input.size();
        if(n<k || k<=0 || n==0) return res;
        if(n==k) return input;
        int index;
        int start=0, end = n-1;
        index = partition(input, start, end);
        while(index!= k-1){
              
            if(index > k-1){
               end = index-1;  //这里要注意
              index = partition(input, start, end);
            }
            else{
                start = index+1;   // 这里要注意
               index = partition(input, start,end);
            }
               
        }
        for(int i=0;i<k;i++)
            res.push_back(input[i]);
        return res;
    }
private:
    int partition(vector<int> & input, int start, int end){
        int target = input[start];
        while(start<end){
            while(start<end && input[end]>target)
                end--;
            input[start]=input[end];
            while(start<end && input[start]<=target)
                start++;
            input[end]=input[start];
        }
        input[start]=target;
        return start;
    }
};

方法三:
时间复杂度O(n log k), `特别适合处理海量数据!!! 只要内存能够容纳leastNumbers即可,因此它最适合的情形就是n很大并且k较小的问题。
C++ multiset通过greater、less指定排序方式,实现最大堆、最小堆功能。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        int len = input.size();
        if(len < k || k<=0 ) return res;
        multiset<int, greater<int> > leastNumbers;
        multiset<int, greater<int>>::iterator iterGreater;
        for(int i=0;i<len;i++){
            if(leastNumbers.size()<k)
                leastNumbers.insert(input[i]);
            else{
                iterGreater = leastNumbers.begin();
                if(input[i] < *iterGreater){
                    leastNumbers.erase(iterGreater);
                    leastNumbers.insert(input[i]);
                }
            }
        }
        for(iterGreater=leastNumbers.begin();iterGreater!=leastNumbers.end();iterGreater++)
            res.push_back(*iterGreater);
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值