leetcode解题思路分析(七十六)670 - 676 题

  1. 最大交换
    给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。

先从低位往高位遍历,保存每一位经过交换能得到的最大值的下标
再从高位往低位遍历,直到某一位小于该位可以取到的最大值,上一步保存了该位置最大值的下标,交换即可

class Solution {
    
    
public:
    int maximumSwap(int num) {
    
    
        string str = to_string(num);
        int n = str.size();
        vector<int> res(n, n);
        int index = n, maxnum = -1;
        for (int i = n - 1; i >= 0; i--) {
    
    
            if (str[i] - '0' > maxnum) {
    
    
                maxnum = str[i] - '0';
                index = i;
            }
            else if (str[i] - '0' < maxnum){
    
    
                res[i] = index;
            }
        }
        for (int i = 0; i < n; i++) {
    
    
            if (res[i] != n) {
    
    
                swap(str[i], str[res[i]]);
                break;
            }
        }
        return stoi(str);
    }
};


  1. 二叉树中第二小的节点
    给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
    更正式地说,root.val = min(root.left.val, root.right.val) 总成立。
    给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

1、 首先根据题目根节点的值一定是最小的值。
2、 根据题目给出的节点条件,可得出以下信息(结合图理解):
a) 第二小的值一定出现在与根节点值相同节点的左右子树上。
b) 根节点的值一定会延伸到至少一个叶子结点,否则就不满足当前节点始终等于左右节点的较小值。

/**
 * 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 {
    
    
public:
    int findSecondMinimumValue(TreeNode* root) {
    
    
        //如果当前节点无左右节点,因为当前节点值一定与根节点值相同,所有没有更大的节点值,返回-1
        if(root->left == nullptr && root->right == nullptr)
            return -1;
        
        int lval = -1,rval = -1;
        //如果左边的节点的值等于根节点的值,则我们需要递归去寻找左子树上大于根节点值的节点值
        if(root->left->val == root->val){
    
    
            lval = findSecondMinimumValue(root->left);
        }else{
    
      //否则直接取出大于根节点值的节点值
            lval = root->left->val;
        }
        
        //右边同理
        if(root->right->val == root->val){
    
    
            rval = findSecondMinimumValue(root->right);
        }else{
    
    
            rval = root->right->val;
        }

        //只要有一个为-1,则返回另一个,否则返回左右的较小值
        if(lval == -1)
            return rval;
        if(rval == -1)
            return lval;
        return min(rval,lval);
    }
};


  1. 灯泡开关2
    现有一个房间,墙上挂有 n 只已经打开的灯泡和 4 个按钮。在进行了 m 次未知操作后,你需要返回这 n 只灯泡可能有多少种不同的状态。

实际是一道脑筋急转弯,变化的数量是有限的,穷举即可

class Solution {
    
    
public:
    int flipLights(int n, int m) {
    
    
        if(n ==0 || m == 0){
    
    
            return 1;
        }
        if(n == 1){
    
    
            return 2;
        }
        else if(n == 2 && m == 1){
    
    
            return 3;
        }
        else if((n == 2 && m >= 2) || m == 1){
    
    
            // n < 3的情况已被前面的if排除
            // 因此当n>=3时,只需判断m==1即可
            return 4;
        }
        else if(n >= 3 && m == 2){
    
    
            return 7;
        }
        else {
    
    
            return 8;
        }
    }
};

  1. 最长递增子序列的个数
    给定一个未排序的整数数组,找到最长递增子序列的个数。

采用动态规划存取以i结尾的数组最长递增子序列长度,如果以j结尾的最大长度和i一样,则总数加1,否则更新新长度。

class Solution {
    
    
public:
    int findNumberOfLIS(vector<int>& nums) {
    
    

        int n = nums.size();
        if(n<=0) return n;

        vector<int> dp(n, 1);
        vector<int> count(n,1);

        for(int i=1; i<n; i++) {
    
    
            for(int j=0; j<i; j++) {
    
    
                if(nums[j] < nums[i]) {
    
    
                    // 第一次找到
                    if(dp[j]+1 > dp[i]) {
    
    
                        dp[i] = dp[j] + 1;
                        count[i] = count[j];
                    // 再次找到
                    } else if(dp[j]+1 == dp[i]) {
    
    
                        count[i] += count[j];
                    }
                }
            }
        }
        // 最后的返回值应该是所有最大长度的所有count的总和
        int max = *max_element(dp.begin(), dp.end());
        int res = 0;
        for(int i=0; i<n; i++) {
    
    
            if(dp[i] == max)
                res += count[i];
        }

        return res;

    }
};

  1. 最长连续递增序列
    给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。

主要思路就是贪心法取最长串,因为如果想最长,那一定得从头开始,如果中间有一个不满足,那只能重新算。

class Solution {
    
    
public:
    int findLengthOfLCIS(vector<int>& nums) {
    
    
        int ans = 0;
        int n = nums.size();
        int start = 0;
        for (int i = 0; i < n; i++) {
    
    
            if (i > 0 && nums[i] <= nums[i - 1]) 
            {
    
    
                start = i;
            }
            else
            {
    
    
                ans = max(ans, i - start + 1);
            }
        }
        return ans;
    }
};
  1. 为高尔夫比赛砍树
    你被请来给一个要举办高尔夫比赛的树林砍树。树林由一个 m x n 的矩阵表示,你需要按照树的高度从低向高砍掉所有的树,每砍过一颗树,该单元格的值变为 1(即变为地面)。你将从 (0, 0) 点开始工作,返回你砍完所有树需要走的最小步数。 如果你无法砍完所有的树,返回 -1 。可以保证的是,没有两棵树的高度是相同的,并且你至少需要砍倒一棵树。

在BFS基础上进行一些优化

int f[3050], vis[3050], sz, m,n,n2;
int q[3050], st[3050];
int tr[3000], cnt;
class Solution {
    
    
public:
    int cutOffTree(vector<vector<int>>& forest) {
    
    
        sz = 0, m = forest.size(), n = forest[0].size(),n2 = n+2, cnt = 0;

        // 数据预处理
        for(int i = 0; i < n2; ++i) f[sz++] = 0;
        tr[cnt++] = sz+1; // 我们需要从 [0,0] 开始
        for(int i = 0; i < forest.size(); ++i) {
    
    
            f[sz++] = 0;
            for(int j = 0; j < forest[0].size(); ++j, ++sz) {
    
    
                f[sz] = forest[i][j];
                if(f[sz] > 1) tr[cnt++] = sz;
            }
            f[sz++] = 0;
        }
        for(int i = 0; i < n2; ++i) f[sz++] = 0;
        memset(vis, 0, sz*sizeof(int));

        // 按树的高度从低向高排序
        sort(tr + 1, tr + cnt, [](int &a, int &b) {
    
    
            return f[a] < f[b];
        });

        // 间隔 bfs
        int res = 0, t[2];
        for(int i = (tr[0] == tr[1]? 2 : 1); i < cnt; i += 2) {
    
    
            t[0] = tr[i-1], t[1] = ((i + 1 == cnt)? -1 : tr[i+1]);
            if(!bfs(i, tr[i], t, 1 + (t[1] != -1), res))
                return -1;
        }
        return res;
    }

    bool bfs(int num, int s, int t[], int obj, int& res) {
    
    
        int got = 0, go[4] = {
    
    1,-1,n2,-n2};
        q[0] = s, st[0] = 0, vis[s] = num;
        for(int r = 0, w = 1; r != w; ++r)
        for(int d = 0; d < 4; ++d) {
    
    
            int ne = q[r] + go[d];
            if(f[ne] && vis[ne] != num) {
    
    
                if(ne == t[0]) res += st[r] + 1, ++got;
                if(ne == t[1]) res += st[r] + 1, ++got;
                if(got == obj) return true;
                vis[ne] = num, q[w] = ne, st[w] = st[r] + 1,++w;
            }
        }
        return false;
    }
};


  1. 实现一个魔法字典
class MagicDictionary {
    
    
public:
    /** Initialize your data structure here. */
    unordered_map<string, vector<string>> container;
    MagicDictionary() {
    
    
        
    }
    
    void buildDict(vector<string> dictionary) {
    
    
        for (auto e : dictionary) {
    
    
            auto proto = e;
            for (int i = 0; i < e.size(); ++i) {
    
    
                char c = e[i];
                e[i] = '_';
                container[e].emplace_back(proto);
                e[i] = c;
            }
        }
    }
    
    bool search(string searchWord) {
    
    
        auto e = searchWord;
        for (int i = 0; i < searchWord.size(); ++i) {
    
    
            char c = searchWord[i];
            searchWord[i] = '_';
            if (container.find(searchWord) != container.end() && (container[searchWord].size() > 1 || container[searchWord][0] != e)) return true;
            searchWord[i] = c;
        }
        return false;
    }
};

/**
 * Your MagicDictionary object will be instantiated and called as such:
 * MagicDictionary* obj = new MagicDictionary();
 * obj->buildDict(dictionary);
 * bool param_2 = obj->search(searchWord);
 */

/**
 * Your MagicDictionary object will be instantiated and called as such:
 * MagicDictionary* obj = new MagicDictionary();
 * obj->buildDict(dictionary);
 * bool param_2 = obj->search(searchWord);
 */

猜你喜欢

转载自blog.csdn.net/u013354486/article/details/117159814