leetcode刷题记录34(2024-3-2)【反转字符串中的单词 III | 按字典序排列最小的等效字符串(并查集) | 分式化简(数学) | 机器人大冒险(模拟)】

557. 反转字符串中的单词 III

给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例 1:

输入:s = “Let’s take LeetCode contest”
输出:“s’teL ekat edoCteeL tsetnoc”

示例 2:

输入: s = “Mr Ding”
输出:“rM gniD”

提示:

  • 1 <= s.length <= 5 ∗ 1 0 4 5 * 10^4 5104
  • s 包含可打印的 ASCII 字符。
  • s 不包含任何开头或结尾空格。
  • s 里 至少 有一个词。
  • s 中的所有单词都用一个空格隔开。

根据空格找到开始和结束的位置,然后原地交换。

class Solution
{
public:
    string reverseWords(string s)
    {
        int i = 0;
        while (i < s.size())
        {
            int start = i;
            while (i < s.size() && s[i] != ' ')
                i++;
            int end = i - 1;
            while (start < end)
            {
                swap(s[start++], s[end--]);
            }
            while (i < s.size() && s[i] == ' ')
                i++;
        }
        return s;
    }
};

1061. 按字典序排列最小的等效字符串

给出长度相同的两个字符串s1 和 s2 ,还有一个字符串 baseStr 。

其中 s1[i] 和 s2[i] 是一组等价字符。

举个例子,如果 s1 = “abc” 且 s2 = “cde”,那么就有 ‘a’ == ‘c’, ‘b’ == ‘d’, ‘c’ == ‘e’。
等价字符遵循任何等价关系的一般规则:

自反性 :‘a’ == ‘a’
对称性 :‘a’ == ‘b’ 则必定有 ‘b’ == ‘a’
传递性 :‘a’ == ‘b’ 且 ‘b’ == ‘c’ 就表明 ‘a’ == ‘c’
例如, s1 = “abc” 和 s2 = “cde” 的等价信息和之前的例子一样,那么 baseStr = “eed” , “acd” 或 “aab”,这三个字符串都是等价的,而 “aab” 是 baseStr 的按字典序最小的等价字符串

利用 s1 和 s2 的等价信息,找出并返回 baseStr 的按字典序排列最小的等价字符串。

示例 1:

输入:s1 = “parker”, s2 = “morris”, baseStr = “parser”
输出:“makkek”
解释:根据 A 和 B 中的等价信息,我们可以将这些字符分为 [m,p], [a,o], [k,r,s], [e,i] 共 4 组。每组中的字符都是等价的,并按字典序排列。所以答案是 “makkek”。

示例 2:

输入:s1 = “hello”, s2 = “world”, baseStr = “hold”
输出:“hdld”
解释:根据 A 和 B 中的等价信息,我们可以将这些字符分为 [h,w], [d,e,o], [l,r] 共 3 组。所以只有 S 中的第二个字符 ‘o’ 变成 ‘d’,最后答案为 “hdld”。

示例 3:

输入:s1 = “leetcode”, s2 = “programs”, baseStr = “sourcecode”
输出:“aauaaaaada”
解释:我们可以把 A 和 B 中的等价字符分为 [a,o,e,r,s,c], [l,p], [g,t] 和 [d,m] 共 4 组,因此 S 中除了 ‘u’ 和 ‘d’ 之外的所有字母都转化成了 ‘a’,最后答案为 “aauaaaaada”。

提示:

1 <= s1.length, s2.length, baseStr <= 1000
s1.length == s2.length
字符串s1, s2, and baseStr 仅由从 ‘a’ 到 ‘z’ 的小写英文字母组成。

把具有等价关系的字母,放到一个集合中去,然后扫描baseStr,将其中的字符串替换成集合中的第一个字母。

#include <string>
#include <vector>
#include <iostream>

using namespace std;

// 加权并查集
class UFSets
{
public:
    vector<int> parent;

    UFSets(int n)
    {
        parent = vector<int>(n);
        for (int i = 0; i < n; i++)
        {
            parent[i] = i;
        }
    }

    int Find(int x)
    {
        if (x != parent[x])
        {
            // 递归进行路径压缩
            parent[x] = Find(parent[x]);
        }
        return parent[x];
    }

    void Union(int x, int y)
    {
        int rootX = Find(x);
        int rootY = Find(y);
        if (rootX == rootY)
        {
            return;
        }
        else if (rootX < rootY)
        {
            parent[rootY] = rootX;
        }
        else
        {
            parent[rootX] = rootY;
        }
    }
};

class Solution
{
public:
    string smallestEquivalentString(string s1, string s2, string baseStr)
    {
        UFSets st(26);
        for (int i = 0; i < s1.size(); i++)
        {
            st.Union(s1[i] - 'a', s2[i] - 'a');
        }
        string res(baseStr.size(), ' ');
        for (int i = 0; i < baseStr.size(); i++)
        {
            res[i] = 'a' + st.Find(baseStr[i] - 'a');
        }
        return res;
    }
};

int main()
{
    string s1 = "abc";
    string s2 = "cde";
    string baseStr = "eed";
    Solution sol;
    string res = sol.smallestEquivalentString(s1, s2, baseStr);
    cout << res;
}

LCP 02. 分式化简

有一个同学在学习分式。他需要将一个连分数化成最简分数,你能帮助他吗?

在这里插入图片描述

连分数是形如上图的分式。在本题中,所有系数都是大于等于0的整数。

输入的cont代表连分数的系数(cont[0]代表上图的 a 0 a_0 a0,以此类推)。返回一个长度为2的数组[n, m],使得连分数的值等于n / m,且n, m最大公约数为1。

示例 1:

输入:cont = [3, 2, 0, 2]
输出:[13, 4]
解释:原连分数等价于3 + (1 / (2 + (1 / (0 + 1 / 2))))。注意[26, 8], [-13, -4]都不是正确答案。

示例 2:

输入:cont = [0, 0, 3]
输出:[3, 1]
解释:如果答案是整数,令分母为1即可。

限制:

cont[i] >= 0
1 <= cont的长度 <= 10
cont最后一个元素不等于0
答案的n, m的取值都能被32位int整型存下(即不超过 2 31 − 1 2 ^ {31} - 1 2311)。

每次计算一个分数线,这包含两个部分,1. 分数相加,2. 颠倒分子分母,然后写一个循环,并处理好边界条件就可以了。值得注意的是,虽然题目中要求将最后的结果化简成最简分数,但是最后一步的运算为一个整数+一个整数分之一,理论上就是最简的,所以就不需要再进行辗转相除来进行化简了,因此下面代码将化简的部分进行了注释。

#include <vector>

using namespace std;

class Solution
{
	// 求解最大公约数
    int divide(int m, int n)
    {
        if (m > n)
            swap(m, n);
        if (n % m == 0)
            return m;
        return divide(m, n - m);
    }

public:
    vector<int> fraction(vector<int> &cont)
    {
        // 特殊情况,没有分数线
        if (cont.size() == 1)
        {
            return {cont[0], 1};
        }

        // 一般情况
        int n = 1, m = cont[cont.size() - 1];
        for (int i = cont.size() - 2; i > 0; i--)
        {
            // 整数加分数(计算加号)
            n += cont[i] * m;
            // 颠倒分子分母(计算分数线)
            swap(n, m);
        }
        n += cont[0] * m;
		// 化简
        // int num = divide(m, n);
        // n = n / num;
        // m = m / num;

        // 返回结果
        return {n, m};
    }
};

LCP 03. 机器人大冒险

力扣团队买了一个可编程机器人,机器人初始位置在原点(0, 0)。小伙伴事先给机器人输入一串指令command,机器人就会无限循环这条指令的步骤进行移动。指令有两种:

U: 向y轴正方向移动一格
R: 向x轴正方向移动一格。
不幸的是,在 xy 平面上还有一些障碍物,他们的坐标用obstacles表示。机器人一旦碰到障碍物就会被损毁。

给定终点坐标(x, y),返回机器人能否完好地到达终点。如果能,返回true;否则返回false。

示例 1:

输入:command = “URR”, obstacles = [], x = 3, y = 2
输出:true
解释:U(0, 1) -> R(1, 1) -> R(2, 1) -> U(2, 2) -> R(3, 2)。

示例 2:

输入:command = “URR”, obstacles = [[2, 2]], x = 3, y = 2
输出:false
解释:机器人在到达终点前会碰到(2, 2)的障碍物。

示例 3:

输入:command = “URR”, obstacles = [[4, 2]], x = 3, y = 2
输出:true
解释:到达终点后,再碰到障碍物也不影响返回结果。

限制:

  1. 2 <= command的长度 <= 1000
  2. command由U,R构成,且至少有一个U,至少有一个R
  3. 0 < = x < = 1 e 9 , 0 < = y < = 1 e 9 0 <= x <= 1e9, 0 <= y <= 1e9 0<=x<=1e9,0<=y<=1e9
  4. 0 <= obstacles的长度 <= 1000
  5. obstacles[i]不为原点或者终点

对该过程进行模拟,依次测试false的情况,如果都不成立,最终返回true,false分为以下情况:

  • 无法走到(x,y);
  • 可以走到(x,y),但中间会遇到障碍;

同时,在进行求解的过程中,需要进行一些优化,比如通过除法降低模拟的轮数;在计算障碍物的时候,如果已经超过了x或y的范围,就说明不会踩到这个障碍物,continue下一个障碍。

#include <string>
#include <vector>

using namespace std;

class Solution
{
    int num_U = 0, num_R = 0;
    string m_command;
    // 判断是否可以走到(x, y)
    bool isArrive(int x, int y)
    {
        if (abs(x / num_R - y / num_U) <= 1)
        {
            int minTime = min(x / num_R, y / num_U);
            int dx = x - minTime * num_R;
            int dy = y - minTime * num_U;
            if (dx == 0 && dy == 0)
                return true;
            for (int i = 0; i < m_command.size(); i++)
            {
                if (m_command[i] == 'U')
                {
                    dy--;
                }
                else
                {
                    dx--;
                }
                if (dx == 0 && dy == 0)
                {
                    return true;
                }
                else if (dx < 0 || dy < 0)
                {
                    return false;
                }
            }
        }
        return false;
    }

public:
    bool robot(string command, vector<vector<int>> &obstacles, int x, int y)
    {
        m_command = command;
        // 统计command中u和r的数量
        for (int i = 0; i < command.size(); i++)
        {
            if (command[i] == 'U')
            {
                num_U++;
            }
            else
            {
                num_R++;
            }
        }

        // 判断是否可以走到目标
        bool res = isArrive(x, y);
        if (!res)
        {
            return false;
        }

        // 判断中间是否会遇到障碍
        for (int i = 0; i < obstacles.size(); i++)
        {
            if (obstacles[i][0] > x || obstacles[i][1] > y)
            {
                continue;
            }
            else
            {
                res = isArrive(obstacles[i][0], obstacles[i][1]);
                if (res)
                {
                    return false;
                }
            }
        }

        return true;
    }
};

int main()
{
    string command = "URRURRR";
    vector<vector<int>> obstacles = {{7, 7}, {0, 5}, {2, 7}, {8, 6}, {8, 7}, {6, 5}, {4, 4}, {0, 3}, {3, 6}};
    Solution sol;
    bool res = sol.robot(command, obstacles, 4915, 1966);
}
  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cherries Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值