其他分享
首页 > 其他分享> > leetcode解题思路分析(一百)860 - 866 题

leetcode解题思路分析(一百)860 - 866 题

作者:互联网

  1. 柠檬水找零
    在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。注意,一开始你手头没有任何零钱。给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

逐个判断即可

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) 
    {
        bool bRet = false;
        int nFiveCnt = 0, nTenCnt = 0;
        
        for (auto n : bills)
        {
            switch(n)
            {
            case 5:
                nFiveCnt++;
                break;

            case 10:
                if (nFiveCnt == 0)
                {
                    goto Exit0;
                }
                else
                {
                    nFiveCnt--;
                    nTenCnt++;
                }
                break;

            case 20:
                if (nTenCnt > 0)
                {
                    if (nFiveCnt == 0)
                    {
                        goto Exit0;
                    }
                    else
                    {
                        nTenCnt--;
                        nFiveCnt--;
                    }
                }
                else
                {
                    if (nFiveCnt < 3)
                    {
                        goto Exit0;
                    }
                    else
                    {
                        nFiveCnt -= 3;
                    }
                }
                break;
            }
        }

        bRet = true;
Exit0:
        return bRet;
    }
};
  1. 翻转矩阵后的得分
    有一个二维矩阵 A 其中每个元素的值为 0 或 1 。移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0。在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和。返回尽可能高的分数。

贪心算法:先让左边第一列全为1(翻转行实现),然后行不动,翻转后续每列使得1比0多,即可

class Solution {
public:
    int matrixScore(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        int ret = m * (1 << (n - 1));

        for (int j = 1; j < n; j++) {
            int nOnes = 0;
            for (int i = 0; i < m; i++) {
                if (grid[i][0] == 1) {
                    nOnes += grid[i][j];
                } else {
                    nOnes += (1 - grid[i][j]); // 如果这一行进行了行反转,则该元素的实际取值为 1 - grid[i][j]
                }
            }
            int k = max(nOnes, m - nOnes);
            ret += k * (1 << (n - j - 1));
        }
        return ret;
    }
};


  1. 和至少为 K 的最短子数组
    返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。如果没有和至少为 K 的非空子数组,返回 -1 。

任何连续子数组内一旦第一个数为负数,说明后面还需要一个正数对数组和进行调节。导致该数组不是最短的。如果第一个数值为非正数,则舍弃该遍历,不为它找子数组求和。同理,在求和过程中,如果前缀和为非正数,可以将它和第一个数值同样处理,舍弃后面的遍历,不再为它找子数组求和。

class Solution {
public:
    int shortestSubarray(vector<int>& nums, int k) {
        if (nums.empty()) return -1;
        int n = nums.size();

        std::vector<long> presum(n + 1);
        for (int i = 1; i <= n; ++i) presum[i] = presum[i - 1] + nums[i - 1];

        int min_len = n + 1;

        std::deque<int> deq;
        for (int j = 0; j <= n; ++j) {

          while (!deq.empty() && presum[j] < presum.at(deq.back())) deq.pop_back();

          while (!deq.empty() && presum[j] - presum.at(deq.front()) >= k) {
            min_len = std::min(min_len, j - deq.front());
            deq.pop_front();
          }

          deq.push_back(j);
        }
        return min_len == n + 1 ? -1 : min_len;
    }
};
  1. 二叉树中所有距离为 K 的结点
    给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。

通过哈希表记录每个节点的父亲节点,遍历距离为k的时候算上父节点就ok了

/**
 * 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 {
    unordered_map<int, TreeNode*> parents;
    vector<int> ans;

    void findParents(TreeNode* node) {
        if (node->left != nullptr) {
            parents[node->left->val] = node;
            findParents(node->left);
        }
        if (node->right != nullptr) {
            parents[node->right->val] = node;
            findParents(node->right);
        }
    }

    void findAns(TreeNode* node, TreeNode* from, int depth, int k) {
        if (node == nullptr) {
            return;
        }
        if (depth == k) {
            ans.push_back(node->val);
            return;
        }
        if (node->left != from) {
            findAns(node->left, node, depth + 1, k);
        }
        if (node->right != from) {
            findAns(node->right, node, depth + 1, k);
        }
        if (parents[node->val] != from) {
            findAns(parents[node->val], node, depth + 1, k);
        }
    }

public:
    vector<int> distanceK(TreeNode* root, TreeNode* target, int k) {
        // 从 root 出发 DFS,记录每个结点的父结点
        findParents(root);

        // 从 target 出发 DFS,寻找所有深度为 k 的结点
        findAns(target, nullptr, 0, k);

        return ans;
    }
};

  1. 获取所有钥匙的最短路径
    给定一个二维网格 grid。 “.” 代表一个空房间, “#” 代表一堵墙, “@” 是起点,(“a”, “b”, …)代表钥匙,(“A”, “B”, …)代表锁。返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。

转化为图+最短路径求取

class Solution {
public:
    struct State{
        int x,y,key;
        State(int x,int y,int key):x(x),y(y),key(key){}
        State():x(0),y(0),key(0){}
    };
    int shortestPathAllKeys(vector<string>& grid) {

        int n=grid.size(),m=grid[0].size();
        int cntKey=0;
        int begX,begY;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j]=='@')begX=i,begY=j;
                if(islower(grid[i][j]))cntKey++;
            }
        }
        int mask=(1<<cntKey)-1;
        int vis[31][31][1<<6];
        memset(vis,0,sizeof(vis));
        const int xx[4]={1,-1,0,0},yy[4]={0,0,1,-1};
        queue<State>que;
        que.push(State(begX,begY,0));
        vis[begX][begY][0]=1;
        int ans=0;
        while(!que.empty()){
            for(int sz=que.size();sz>0;sz--){
                auto curState=que.front();que.pop();
                int curKey=curState.key,curX=curState.x,curY=curState.y;
                if((curKey&mask)==mask)return ans;
                for(int i=0;i<4;i++){
                    int dx=xx[i]+curX,dy=yy[i]+curY;
                    if(dx<0||dx>=n||dy<0||dy>=m)continue;
                    char c=grid[dx][dy];
                    if(c=='#')continue;
                    int nexKey=curKey;
                    if(islower(c)){
                        nexKey|=(1<<(c-'a'));
                    }
                    if(isupper(c)){
                        int needKey=c-'A';
                        if(((curKey>>needKey)&1)!=1)continue;
                    }
                    if(vis[dx][dy][nexKey]==1)continue;
                    vis[dx][dy][nexKey]=1;
                    que.push(State(dx,dy,nexKey));
                }
            }
            ans++;
        }
        return -1;
    }
};


  1. 具有所有最深节点的最小子树
    给定一个根为 root 的二叉树,每个节点的深度是 该节点到根的最短距离 。如果一个节点在 整个树 的任意节点之间具有最大的深度,则该节点是 最深的 。一个节点的 子树 是该节点加上它的所有后代的集合。返回能满足 以该节点为根的子树中包含所有最深的节点 这一条件的具有最大深度的节点。

题目表述很絮叨,其实就是左右子树深度相等的节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    int GetDepth(TreeNode* node)
    {
        if (node == nullptr)
        {
            return 0;
        }
        return max(GetDepth(node->left), GetDepth(node->right)) + 1;
    }

public:
    TreeNode* subtreeWithAllDeepest(TreeNode* root) {
        if (root == nullptr)
        {
            return nullptr;
        }

        int l = GetDepth(root->left);
        int r = GetDepth(root->right);
        // 如果深度一样,那么就是可以返回子树
        if (l == r)
        {
            return root;
        }
        // 对于深度不一样的情况,就走深度大的分支即可
        return (l > r) ? subtreeWithAllDeepest(root->left) : subtreeWithAllDeepest(root->right);
    }
};


  1. 回文素数
    求出大于或等于 N 的最小回文素数。回顾一下,如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数。例如,2,3,5,7,11 以及 13 是素数。回顾一下,如果一个数从左往右读与从右往左读是一样的,那么这个数是回文数。例如,12321 是回文数。

挨个判断是否是素数是否是回文

class Solution {
public:
    int primePalindrome(int n) {
        while(1){
            string s=to_string(n);
            int sz=s.size();
            string beg=s.substr(0,sz/2);
            string rev=beg;
            reverse(rev.begin(),rev.end());
            string connectStr=s;
            if(sz>1)connectStr=beg+(sz%2==0?"":string(1,s[sz/2]))+rev;
            int connectNum=stoi(connectStr);
            if(connectNum>=n){
                if(isPrime(connectNum))return connectNum;
            }
            if(connectNum<=n) {
                string addOneStr=s.substr(0,(sz+1)/2);
                int addOneNum=stoi(addOneStr);
                addOneNum++;
                addOneStr=to_string(addOneNum);
                rev=addOneStr.substr(0,sz/2);
                reverse(rev.begin(),rev.end());
                connectStr=to_string(addOneNum)+rev;
                connectNum=stoi(connectStr);
                if(isPrime(connectNum))return connectNum;
            }
            n=connectNum;
        }
        return -1;
    }
    bool isPrime(int num){
        if(num<2)return false;
        for(int i=2;i*i<=num;i++){
            if(num%i==0)return false;
        }
        return true;
    }
};

标签:node,right,TreeNode,int,860,866,return,leetcode,left
来源: https://blog.csdn.net/u013354486/article/details/121619565