501. Find Mode in Binary Search Tree\492. Construct the Rectangle\*486. Predict the Winner\输出一个level

501. Find Mode in Binary Search Tree

题目描述

Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently occurred element) in the given BST.

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less than or equal to the node’s key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
  • Both the left and right subtrees must also be binary search trees.

For example:

Given BST [1,null,2,2],

   1
    \
     2
    /
   2

return [2].

Note: If a tree has more than one mode, you can return them in any order.

Follow up: Could you do that without using any extra space? (Assume that the implicit stack space incurred due to recursion does not count).

在二叉树中,找到重复出现次数最多的数字。

代码实现

使用递归我比较习惯使用引用或者全局变量的方法,所以在使用的时候一般会把结果存在引用或者是全局变量里面。

这里我的想法是使用中序遍历,就可以按照大小顺序对二叉树进行一次遍历。

所以代码实现如下:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    void findModes(TreeNode* root) {
        if(!root) return;
        findModes(root->left);
        if(cnt && root->val == lst) cnt++;
        else { lst = root->val; cnt = 1; }
        if(cnt > max_cnt) {
            res.clear();
            res.push_back(lst);
            max_cnt = cnt;
        }
        else if(cnt == max_cnt) res.push_back(lst);
        findModes(root->right);
    }
public:
    int cnt = 0, lst, max_cnt = 0;
    vector<int> res;

    vector<int> findMode(TreeNode* root) {
        findModes(root);    
        return res;
    }
};

492. Construct the Rectangle

题目描述

For a web developer, it is very important to know how to design a web page’s size. So, given a specific rectangular web page’s area, your job by now is to design a rectangular web page, whose length L and width W satisfy the following requirements:

  1. The area of the rectangular web page you designed must equal to the given target area.

  2. The width W should not be larger than the length L, which means L >= W.

  3. The difference between length L and width W should be as small as possible.

You need to output the length L and the width W of the web page you designed in sequence.

Example:

Input: 4
Output: [2, 2]

Explanation: The target area is 4, and all the possible ways to construct it are [1,4], [2,2], [4,1].
But according to requirement 2, [1,4] is illegal; according to requirement 3, [4,1] is not optimal compared to [2,2]. So the length L is 2, and the width W is 2.

Note:

  • The given area won’t exceed 10,000,000 and is a positive integer
  • The web page’s width and length you designed must be positive integers.

    给出面积,计算一个矩形的长和宽,长和宽要尽可能相似。

代码实现

从开根号的地方开始计算起,这是长的最小值。

class Solution {
public:
    vector<int> constructRectangle(int area) {
        vector<int> res(2, 0);
        for(int i = ceil(sqrt(area)); i <= area; i++) {
            int W = floor(area*1.0/i);
            if(W == ceil(area*1.0/i)) {
                res[0] = i; res[1] = W;
                return res;
            }    
        }
        return res;
    }
};

486. Predict the Winner

题目描述

Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.

Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.

Example 1:

Input: [1, 5, 2]
Output: False

Explanation: Initially, player 1 can choose between 1 and 2.
If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. If player 2 chooses 5, then player 1 will be left with 1 (or 2).

So, final score of player 1 is 1 + 2 = 3, and player 2 is 5.

Hence, player 1 will never be the winner and you need to return False.

Example 2:

Input: [1, 5, 233, 7]
Output: True

Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. No matter which number player 2 choose, player 1 can choose 233.
Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win.

Note:
1 <= length of the array <= 20.

Any scores in the given array are non-negative integers and will not exceed 10,000,000.
If the scores of both players are equal, then player 1 is still the winner.

这道题目就是说一个非负整数的数组,然后一个人A从数组的首尾去数字,取完之后这个数字就不在原数组了,A的score加上去的数字。然后是B从剩下的数组的首尾去一个数字。接着轮到A,以此类推,直到结束。

最后判断A和B谁的分数多,如果A的分数多,就返回true,否则就是false。

代码实现

开始的时候我是想用贪心算法来做这个,就是取能够让当前的获利最大的策略。就是看取了一个数ni之后的数组可以供另外一个人取的数字更大值nj之间的差,目标是让这个差更小。

很显然,使用贪心法不能得到最优解。

比如下面这个例子就

class Solution {
public:
    bool PredictTheWinner(vector<int>& nums) {
        int lst = nums.size() - 1;
        int stt = 0;
        int score1 = 0, score2 = 0;
        bool turn1 = true; // if true, player 1 chooses a number.
        while(stt <= lst) {
            int num = 0;
            if(lst - stt <= 2) {
                if(nums[stt] > nums[lst]) {
                    num = nums[stt]; stt++;
                }
                else {
                    num = nums[lst]; lst--;
                }
            }
            else {
                int diff = nums[stt] - max(nums[stt+1], nums[lst]) - nums[lst] + max(nums[stt], nums[lst-1]);
                if(diff >= 0) {
                    num = nums[stt];  stt++;
                }
                else {
                    num = nums[lst];  lst--;
                }
            }
            if(turn1) score1 += num;
            else score2 += num;
            turn1 = !turn1;
        }
        return score1 >= score2;
    }
};

改成DP:DP这个东西其实可以理解为先计算了最小的长度,比如长度为1的时候的得分,然后是长度为2,为3等等,直到为n,就是题目中要求的东西。就是在求解一个问题的时候使用到了之前的值,这样就可以节约很多计算量。一个问题可以分解成更小的问题,更小问题的节为更大的问题节约了计算量。

class Solution {
public:
    bool PredictTheWinner(vector<int>& nums) {
        int len = nums.size();
        vector<vector<int>> score(len, vector<int>(len));
        vector<int> cumSum(len + 1, 0);
        for(int i = 0; i < len; i++) cumSum[i+1] =cumSum[i] + nums[i];

        for(int cur_len = 1; cur_len <= len; cur_len++) {
            for(int left_node = 0; left_node + cur_len - 1 < len; left_node++) {
                int right_node = left_node + cur_len - 1;
                if(left_node == right_node) score[left_node][right_node] = nums[left_node];
                else if(left_node + 1 == right_node) score[left_node][right_node] = max(nums[left_node], nums[right_node]);
                else {
                    int pick_left = nums[left_node] + cumSum[right_node + 1] - cumSum[left_node + 1] - score[left_node+1][right_node];
                    int pick_right = nums[right_node] + cumSum[right_node] - cumSum[left_node] - score[left_node][right_node-1];
                    score[left_node][right_node] = max(pick_left, pick_right);
                }
            }
        }

        return score[0][len-1] >= (cumSum[len]>>1) + (cumSum[len]&1);
    }
};

在上面的解法中,最开始我们要计算的是Player 1是否会赢,这个问题转化为了Player 1能否得到不少于一半的分数。然后这个问题转化为如何求解Player 1得到的最大分数score[0][n-1]。

然后根据规则,这个问题又可以转化为:
score[i][j] = max(sum[i+1][j] - score[i+1][j] + nums[i], sum[i][j-1] - score[i][j-1] + nums[j])

其中 score[i+1][j] 是Player 2在[i+1,j]能够取得的分数,score[i][j-1]同理。

使用sum[i+1][j] - score[i+1][j]计算的得到的就是Player 1在这个范围内能得到的最大分数。当然这里的策略就是Player 1和Player 2都是想得到最大的分数。

然后是在长度为0和1的时候,score的设置。这样的话,我们就完成了整个过程。

我们可以发现其实计算长度的时候是先计算短的,然后是长的。这样的好处就是节约了很多计算量,很多距离得以复用。如果使用暴力破解的话,计算复杂度会提高很多。

参考链接:https://discuss.leetcode.com/topic/76472/clean-3ms-c-dp-solution-with-detailed-explanation

K level

题目描述

对于一棵二叉树,请设计一个算法,创建含有某一深度上所有结点的链表。

给定二叉树的根结点指针TreeNode* root,以及链表上结点的深度,请返回一个链表ListNode,代表该深度上所有结点的值,请按树上从左往右的顺序链接,保证深度不超过树的高度,树上结点的值为非负整数且不超过100000。

代码实现

使用BFS实现这个算法。

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

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class TreeLevel {
public:
    ListNode* getTreeLevel(TreeNode* root, int dep) {
        // write code here
        queue<TreeNode*> que;
        // 这里要注意,之前我是用了ListNode* res(0);
        ListNode* res = new ListNode(0);
        ListNode* net = NULL;
        que.push(root);
        while(!que.empty()) {
            dep--;
            int sz = que.size();
            if(!dep) {
                for(int i = 0; i < sz; i++) {
                    TreeNode *tp = que.front();
                    que.pop();
                    if(tp) {
                        ListNode *cur = new ListNode(tp->val);
                        if(!net) { net = cur; res->next = net; }
                        else {
                            net->next = cur;
                            net = cur;
                        }    
                    }
                }
                break;    
            }
            else {
                for(int i = 0; i < sz; i++) {
                    TreeNode *tp = que.front();
                    que.pop();
                    if(tp) {
                        que.push(tp->left);
                        que.push(tp->right);
                    }
                }    
            }
        }

        return res->next;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值