剑指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]结尾的子数组最大和
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值