Leetcode C++ 《第199场周赛》

做周赛的时候,注意力很集中哈哈,enjoy这个感觉,木有浮躁~
做完之后看大佬写的代码,惊叹且学习了新思路和方法,很开森~

1. 题目1

1.1 问题

https://leetcode-cn.com/contest/weekly-contest-199/problems/shuffle-string/

给你一个字符串 s 和一个 长度相同 的整数数组 indices 。

请你重新排列字符串 s ,其中第 i 个字符需要移动到 indices[i] 指示的位置。

返回重新排列后的字符串。
输入:s = “codeleet”, indices = [4,5,6,7,0,2,1,3]
输出:“leetcode”
解释:如图所示,“codeleet” 重新排列后变为 “leetcode” 。

1.2 思路
  • 暴力替换
1.3 代码
class Solution {
public:
    string restoreString(string s, vector<int>& indices) {
        string res = s;
        for (int i = 0; i < indices.size(); i++) {
            res[indices[i]] = s[i];
        }
        return res;
    }
};

2. 题目2

https://leetcode-cn.com/contest/weekly-contest-199/problems/bulb-switcher-iv/

2.1 问题

房间中有 n 个灯泡,编号从 0 到 n-1 ,自左向右排成一行。最开始的时候,所有的灯泡都是 关 着的。

请你设法使得灯泡的开关状态和 target 描述的状态一致,其中 target[i] 等于 1 第 i 个灯泡是开着的,等于 0 意味着第 i 个灯是关着的。

有一个开关可以用于翻转灯泡的状态,翻转操作定义如下:

选择当前配置下的任意一个灯泡(下标为 i )
翻转下标从 i 到 n-1 的每个灯泡
翻转时,如果灯泡的状态为 0 就变为 1,为 1 就变为 0 。

返回达成 target 描述的状态所需的 最少 翻转次数。

示例 1:

输入:target = “10111”
输出:3
解释:初始配置 “00000”.
从第 3 个灯泡(下标为 2)开始翻转 “00000” -> “00111”
从第 1 个灯泡(下标为 0)开始翻转 “00111” -> “11000”
从第 2 个灯泡(下标为 1)开始翻转 “11000” -> “10111”
至少需要翻转 3 次才能达成 target 描述的状态

2.2 思路
  • bfs超时,太多无效操作了
  • 使用直接逼近答案法,翻转,见AC代码
2.3 超时代码
class Solution {
public:
    string targetStr;
    int minFlips(string target) {
        targetStr = target;
        return bfs();

    }
    
    int  bfs() {
        queue<string> temps;
        map<string, bool> exists;
        string tempStr = "";
        int n = targetStr.length();
        for (int i = 0; i < n; i++)
            tempStr += '0';
        temps.push(tempStr);
        exists.insert(make_pair(tempStr, true));
        int depth = 0;
        while(!temps.empty()) {
            int levelNum = temps.size();
            for (int k = 0; k < levelNum; k++) {
                tempStr = temps.front();
                temps.pop();
                //cout << tempStr << endl;
                if (tempStr == targetStr)
                    return depth;
                for (int i = n-1; i >= 0; i--) {
                    if (tempStr[i] == '1')
                        tempStr[i] = '0';
                    else
                        tempStr[i] = '1';
                    if (!exists.count(tempStr)) {
                        temps.push(tempStr);
                        exists.insert(make_pair(tempStr, true));
                    }
                }
            }
            depth++;
        }
        return depth;
    }
};
2.4 AC代码
class Solution {
public:

    int minFlips(string target) {
        //就说有巧妙的方法,我一根筋的在bfs
        // 如果位置1,证明要翻转,从左到右逐渐趋紧最优解
        //101
        //
        int cur = 0; 
        int res = 0;
        for (int i = 0; i < target.length(); i++) {
            int curPos = target[i] - '0'; //0 or 1
            if (curPos ^ cur == 1) {  // 当前异或是1,证明变成当前操作需要一次翻转,而且之后的每一位都变成了翻转后的值
                cur = cur ^ 1; // 异或操作 00=1
                res ++;
            }
        }
        return res;

    }
};

3. 题目3

3.1 问题

https://leetcode-cn.com/contest/weekly-contest-199/problems/number-of-good-leaf-nodes-pairs/
5474. 好叶子节点对的数量

给你二叉树的根节点 root 和一个整数 distance 。

如果二叉树中两个 叶 节点之间的 最短路径长度 小于或者等于 distance ,那它们就可以构成一组 好叶子节点对 。

返回树中 好叶子节点对的数量 。

3.2 思路
  • 找到所有的叶子节点
  • 然后找叶子节点的最短路径长度【可以通过最低公共祖先;也可以利用二叉树的路径长度左节点为0,右节点为1】
3.3 超时代码
/**
 * 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:
    vector<TreeNode*> leaves;
    int countPairs(TreeNode* root, int distance) {
        //暴力法就是先找到所有的叶子节点n,然后任意两个最短路径如果小于等于distance
        traverse(root);
        int res = 0;
        for (int i = 0; i < leaves.size(); i++) {
            for (int j = i+1; j < leaves.size(); j++) {
                TreeNode* leaf1 = leaves[i];
                TreeNode* leaf2 = leaves[j];
                
                TreeNode* par = lowestCommonAncestor(root, leaf1, leaf2);
                int disTemp = getLength(leaf1, leaf2, par);
                //cout << leaf1->val << " " << leaf2->val  << ": " << disTemp << endl;
                if ( disTemp <= distance)
                    res++;
            }
        }
        return res;
    }
    
    void traverse(TreeNode* root) {
        if (root == NULL)
            return;
        traverse(root->left);
        traverse(root->right);
        if (root->left == NULL && root->right== NULL)
            leaves.push_back(root);
    }
    
    int getLength(TreeNode* leaf1, TreeNode* leaf2, TreeNode* par) {
        int res = 0;
        queue<TreeNode*> nodes;
        nodes.push(par);
        int len1 = -1;
        int len2 = -1;
        int depth=0;
        while(!nodes.empty()) {
            int n = nodes.size();
            for (int i = 0; i < n; i++) {
                TreeNode* t = nodes.front();
                nodes.pop();
                if (t == leaf1)
                    len1 = depth;
                if (t == leaf2)
                    len2 = depth;
                if (len1 != -1 && len2 != -1)
                    break;
                if (t->left != NULL) {
                    nodes.push(t->left);
                }
                if (t->right != NULL) {
                    nodes.push(t->right);
                }
            }
            depth++;
        }
        return len1+len2;
    }
    
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){
		
		//发现目标节点则通过返回值标记该子树发现了某个目标节点
		if (root == NULL || root == p || root == q) {
			
			return root;
			
		}
		
		//查看左子树中是否有目标节点,没有为null
		TreeNode* left = lowestCommonAncestor(root->left, p, q);
		//查看右子树中是否有目标节点,没有为null
		TreeNode* right = lowestCommonAncestor(root->right, p, q);
		//都不为空,则说明左右子树都有目标节点,则公共祖先就是本身。
		if (left != NULL && right != NULL) {
			return root;
		}
		return left == NULL ? right : left;
    }
};
3.4 AC代码
  • leaves 其实可以不要
/**
 * 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:
    vector<TreeNode*> leaves;
    vector<string> paths;
    int countPairs(TreeNode* root, int distance) {
        //暴力法就是先找到所有的叶子节点n,然后任意两个最短路径如果小于等于distance,leaves其实没必要
        traverse(root, "");
        int res = 0;
        for (int i = 0; i < leaves.size(); i++) {
            for (int j = i+1; j < leaves.size(); j++) {
                int disTemp = paths[i].length() + paths[j].length();
                for  (int k = 0; k < paths[i].length() && k < paths[j].length(); k++) {
                    if (paths[i][k] == paths[j][k])
                        disTemp-=2;
                    else 
                        break;
                }
                if ( disTemp <= distance)
                    res++;
            }
        }
        return res;
    }
    
    void traverse(TreeNode* root, string path) {
        if (root == NULL)
            return;
        traverse(root->left, path+'0');
        traverse(root->right, path+'1');
        if (root->left == NULL && root->right== NULL) {
            leaves.push_back(root);
            paths.push_back(path);
        }   
    }  
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值