劍指offer(三)

21. 棧的壓入、彈出序列

在這裏插入圖片描述

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

22. 從上往下打印二叉樹

在這裏插入圖片描述

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        
        vector<int> ret;
        if(!root)
            return ret;
        
        queue<TreeNode*> q;
        q.push(root);
        
        while(!q.empty())
        {
            TreeNode *node = q.front();
            q.pop();
            ret.push_back(node->val);
            
            if(node->left)
                q.push(node->left);
            if(node->right)
                q.push(node->right);
        }
        
        return ret;
    }
};

23. 二叉搜索樹的後序遍歷序列

在這裏插入圖片描述

二叉搜索樹(二叉排序樹):

  • 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值
class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {

        if(sequence.size() == 0)
            return false;
        
        return help(sequence, 0, sequence.size()-1);
    }
    
private:
    bool help(const vector<int>& sequence, int l, int r)
    {
        if(l >= r)
            return true;
        
        int target = sequence[r];                //根節點值
        int i = l;
        while(sequence[i] < target && i < r)     //左子樹 < 根節點值
            i++;
        
        int mid = i-1;
        for(; i< r; i++)
        {
            if(sequence[i] <= target)
                return false;
        }
        
        return help(sequence, l, mid) && help(sequence, mid+1, r-1);
    }
};

24.二叉樹中和爲某一值的路徑

在這裏插入圖片描述

/*
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> > FindPath(TreeNode* root,int expectNumber) {

        vector<vector<int>> ret;
        if(!root)
            return ret;
        
        vector<int> v;
        help(root, expectNumber, ret, v);
        
        return ret;
    }
    
private:
    void help(TreeNode *node, int expectNumber, vector<vector<int>> &ret, vector<int> &v)
    {
        
        v.push_back(node->val);
        
        if(!node->left && !node->right && node->val == expectNumber)
        {
            ret.push_back(v);
        }
       
        
        if(node->left)
        {
            help(node->left, expectNumber-node->val, ret, v);
        }
        
        if(node->right)
        {
            help(node->right, expectNumber-node->val, ret, v);
        }
        
        v.pop_back();
    }
};

25. 複雜鏈表的複製

在這裏插入圖片描述

方法一:

  • 第一遍構建next指針,同時保存random信息到 map<RandomListNode , RandomListNode >
  • 第二遍根據 map 信息構建random
/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(!pHead)
            return pHead;
        
        RandomListNode *newHead = new RandomListNode(pHead->label);
        m[pHead] = newHead;
        
        RandomListNode *curP = pHead->next;
        RandomListNode *curN = newHead;
        while(curP)
        {
            RandomListNode *node = new RandomListNode(curP->label);
            curN->next = node;
            
            m[curP] = node;
            
            curP = curP->next;
            curN = curN->next;
        }
        
        curP = pHead;
        curN = newHead;
        while(curP)
        {
            if(curP->random)
            {
                RandomListNode *tmp = curP->random;
                curN->random = m[tmp];
            }
            
            curP = curP->next;
            curN = curN->next;
        }
        
        return newHead;
    }
    
private:
    map<RandomListNode*, RandomListNode*> m;		//first:保存原始鏈表節點	second:保存對應的新鏈表節點
};

方法二:

  • 將每個新建的節點放在對應原節點之後
  • 原節點的random的next爲新節點的random
  • 分離兩個鏈表
/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(!pHead)
            return pHead;
        
        RandomListNode *cur = pHead;
        while(cur)                            //構建 next
        {
            RandomListNode *node = new RandomListNode(cur->label);
            node->next = cur->next;
            cur->next = node;
            
            cur = node->next;
        }
        
        cur = pHead;
        while(cur)                            //構建 random
        {
            RandomListNode *node = cur->next;
            if(cur->random)
            {
                node->random = cur->random->next;
            }
            
            cur = node->next;
        }
        
        cur = pHead;
        RandomListNode *ret = cur->next;
        while(cur->next)                    //分離鏈表  務必畫圖
        {
            RandomListNode *newN = cur->next;
            cur->next = cur->next->next;
            cur = newN;
        }
        
        return ret;
    }

};

26. 二叉搜索樹與雙向鏈表

在這裏插入圖片描述

方法一:

  • 中序遍歷,將節點保存在 vector
  • 遍歷vector,將節點的 left 指向前一個節點,right 指向後一個節點
/*
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) || (!pRootOfTree->left) && (!pRootOfTree->right))
            return pRootOfTree;
        inOrder(pRootOfTree);
        nodeVector[0]->left = NULL;
        nodeVector[0]->right = nodeVector[1];
        int i = 1;
        for( ; i < nodeVector.size() - 1; i ++)
        {
            nodeVector[i]->left = nodeVector[i - 1];
            nodeVector[i]->right = nodeVector[i + 1];
        }
        nodeVector[i]->left = nodeVector[i - 1];
        nodeVector[i]->right = NULL;
        return nodeVector[0];
    }
    
private:
    vector<TreeNode *> nodeVector;

    void inOrder(TreeNode* root)
    {
        if(root->left)
            inOrder(root->left);
        nodeVector.push_back(root);
        if(root->right)
            inOrder(root->right);
    }
};

方法二:

  • 將左子樹變爲有序的排序鏈表,
  • 再將右子樹變爲有序的鏈表,
  • 然後將當前結點插入到兩個鏈表中間
/*
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)
            return pRootOfTree;
        
        TreeNode *lNode = Convert(pRootOfTree->left);
        TreeNode *rNode = Convert(pRootOfTree->right);
        
        TreeNode *node = lNode;
        if(node)
        {
            while(node->right)                //找到左鏈表的最後一個節點
                node = node->right;
            
            node->right = pRootOfTree;
        }
        pRootOfTree->left = node;
        
        if(rNode)
            rNode->left = pRootOfTree;
        pRootOfTree->right = rNode;
        
        return (lNode)?lNode:pRootOfTree;
    }

};

27. 字符串的排列

在這裏插入圖片描述

class Solution {
public:
    vector<string> Permutation(string str) {       
        
        if(str.length() == 0)
            return vector<string>();
        
        visited = vector<bool>(str.length(), false);
        
        string s;
        help(str, 0, s);
        
        vector<string> v(s_.begin(), s_.end());
        return v;
    }
    
private:
    set<string> s_;            //去重
    vector<bool> visited;
    
    void help(const string &str, int index, string s)
    {
        if(index == str.length())
        {
            s_.insert(s);
            return ;
        }
        
        for(int i=0; i<str.length(); i++)
        {
            if(!visited[i])
            {
                visited[i] = true;
                help(str, index+1, s+str[i]);
                visited[i] = false;
            }
        }
    }
};

28. 數組中出現次數超過一半的數字

在這裏插入圖片描述

方法一:

  • 用map統計數字出現的次數
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
    
        for(int i=0; i<numbers.size(); i++)
        {
            int num = ++m[numbers[i]];
            if(num > numbers.size()/2)
                return numbers[i];
        }
        
        return 0;
    }
    
private:
    map<int, int> m;
};

方法二:

  • 數組排序後,如果符合條件的數存在,則一定是數組中間那個數
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
    
        sort(numbers.begin(), numbers.end());
        
        int n = numbers.size();
        int mid = numbers[n/2];
        int ret = 0;
        for(int i=0; i<n; i++)
        {
            if(numbers[i] == mid)
                ret++;
        }
        
        
        return (ret>n/2)?mid:0;
    }
 
};

方法三:

  • 如果符合條件的數存在,則其他數字出現的次數和要小於這個數
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
    
        int num = numbers[0];
        int index = 1;
        
        for(int i=1; i<numbers.size(); i++)
        {
            if(index == 0)
            {
                num = numbers[i];
                index = 1;
                continue;
            }
            
            if(num == numbers[i])
                index++;
            else
                index--;
            
        }
        
        //判斷是否符合條件
        int count = 0;
        for(int i=0; i<numbers.size(); i++)
        {
            if(numbers[i] == num)
                count++;
        }
        
        return (count>numbers.size()/2)?num:0;
    }
 
};

29. 最小的K個數

在這裏插入圖片描述

方法一:

  • 大根堆
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        
        vector<int> ret;
        if(input.size() < k)
            return ret;
        
        for(int i=0; i<input.size(); i++)
        {
            if(pq.size()<=k || pq.top() > input[i])
                pq.push(input[i]);
            
            if(pq.size() > k)
                pq.pop();
        }
        
        while(pq.size() > 0)
        {
            ret.push_back(pq.top());
            pq.pop();
        }
       
        return ret;
    }
    
private:
    priority_queue<int> pq;
};

方法二:

  • 排序

30. 連續子數組的最大和

在這裏插入圖片描述

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
    
        int maxSum = INT_MIN;
        int sum = 0;
        for(int i=0; i<array.size(); i++)
        {
            sum += array[i];
            if(sum > maxSum)
                maxSum = sum;
            if(sum < 0)            //在每次元素累加和小於0時,從下一個元素重新開始累加
                sum = 0;
        }
        
        return maxSum;
    }
};

動態規劃

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
    
        memo = vector<int>(array.size(), -1);
        memo[0] = array[0];
         
        for(int i=1; i<array.size(); i++)
        {
            memo[i] = max(memo[i-1]+array[i], array[i]);
        }
        
        sort(memo.begin(), memo.end());
        return memo[array.size()-1];
    }
    
private:
    vector<int> memo;    //memo[i]:以array[i]結尾的子數組最大和
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章