leetcode解题思路分析(一百六十二)1401 - 1408 题

  1. 圆和矩形是否有重叠
    给你一个以 (radius, xCenter, yCenter) 表示的圆和一个与坐标轴平行的矩形 (x1, y1, x2, y2) ,其中 (x1, y1) 是矩形左下角的坐标,而 (x2, y2) 是右上角的坐标。如果圆和矩形有重叠的部分,请你返回 true ,否则返回 false 。换句话说,请你检测是否 存在 点 (xi, yi) ,它既在圆上也在矩形上(两者都包括点落在边界上的情况)

求圆和直线的位置关系时,我们常常会计算圆心到直线的垂直线段的距离。这条垂直线段的距离小于半径的时候,就说明两者相交

cpp 复制代码
class Solution {
public:
    bool checkOverlap(int radius, int xCenter, int yCenter, int x1, int y1, int x2, int y2) {
        long long dist = 0;
        if (xCenter < x1 || xCenter > x2) {
            dist += min(pow(x1 - xCenter, 2), pow(x2 - xCenter, 2));
        }
        if (yCenter < y1 || yCenter > y2) {
            dist += min(pow(y1 - yCenter, 2), pow(y2 - yCenter, 2));
        }
        return dist <= radius * radius;
    }
};
  1. 做菜顺序
    一个厨师收集了他 n 道菜的满意程度 satisfaction ,这个厨师做出每道菜的时间都是 1 单位时间。一道菜的 「 like-time 系数 」定义为烹饪这道菜结束的时间(包含之前每道菜所花费的时间)乘以这道菜的满意程度,也就是 time[i]*satisfaction[i] 。返回厨师在准备了一定数量的菜肴后可以获得的最大 like-time 系数 总和。你可以按 任意 顺序安排做菜的顺序,你也可以选择放弃做某些菜来获得更大的总和。

本题最难的其实是理解题意。只要理解了多道菜会有time[i]系数加成就好做了。排序后,每次算一下,总值更大就继续下一个,否则退出。

cpp 复制代码
class Solution {
public:
    int maxSatisfaction(vector<int>& satisfaction) {
        sort(satisfaction.begin(), satisfaction.end(), greater<int>());
        int presum = 0, ans = 0;
        for (int si: satisfaction) {
            if (presum + si > 0) {
                presum += si;
                ans += presum;
            } else {
                break;
            }
        }
        return ans;
    }
};
  1. 非递增顺序的最小子序列
    给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和。如果存在多个解决方案,只需返回 长度最小 的子序列。如果仍然有多个解决方案,则返回 元素之和最大 的子序列。与子数组不同的地方在于,「数组的子序列」不强调元素在原数组中的连续性,也就是说,它可以通过从数组中分离一些(也可能不分离)元素得到。注意,题目数据保证满足所有约束条件的解决方案是 唯一 的。同时,返回的答案应当按 非递增顺序 排列。

排序后挨个加即可

cpp 复制代码
class Solution {
public:
    vector<int> minSubsequence(vector<int>& nums) {
        int sum = 0;
        for (auto n : nums) {
            sum += n;
        }
        sort(nums.begin(), nums.end(), greater<int>());

        vector<int> ret;
        int sub_sum = 0;
        for (int i = 0; i < nums.size(); ++i) {
            sub_sum += nums[i];
            ret.push_back(nums[i]);
            if (sub_sum > sum / 2)
                break;
        }

        return ret;
    }
};
  1. 将二进制表示减到 1 的步骤数
    给你一个以二进制形式表示的数字 s 。请你返回按下述规则将其减少到 1 所需要的步骤数:如果当前数字为偶数,则将其除以 2 。如果当前数字为奇数,则将其加上 1 。题目保证你总是可以按上述规则将测试用例变为 1 。

直接模拟就完事

cpp 复制代码
class Solution {
public:
    int numSteps(string s) {
        int steps = 0;
        while (s != "1") {
            ++steps;
            if (s.back() == '0') {
                // 偶数的情况
                s.pop_back();
            }
            else {
                // 第一步:找出最低位的 0
                // 第二步:把这个 0 变成 1,并将后面所有的 1 变成 0,这样就实现了 +1
                // 特别地,如果 s 中全是 1,那么会有额外的进位
                for (int i = s.size() - 1; i >= 0; --i) {
                    if (s[i] == '1') {
                        s[i] = '0';
                        if (i == 0) {
                            s = "1" + s;
                            break;
                        }
                    }
                    else {
                        s[i] = '1';
                        break;
                    }
                }
            }
        }
        return steps;
    }
};
  1. 最长快乐字符串
    如果字符串中不含有任何 'aaa','bbb' 或 'ccc' 这样的字符串作为子串,那么该字符串就是一个「快乐字符串」。给你三个整数 a,b ,c,请你返回 任意一个 满足下列全部条件的字符串 s:s 是一个尽可能长的快乐字符串。s 中 最多 有a 个字母 'a'、b 个字母 'b'、c 个字母 'c' 。s 中只含有 'a'、'b' 、'c' 三种字母。如果不存在这样的字符串 s ,请返回一个空字符串 ""。

贪心算法:每次每个都最多填2个,优先填剩下最多的。

cpp 复制代码
class Solution {
public:
    string longestDiverseString(int a, int b, int c) {
        string res;
        vector<pair<int, char>> arr = {{a, 'a'}, {b, 'b'}, {c, 'c'}};
        
        while (true) {
            sort(arr.begin(), arr.end(), [](const pair<int, char> & p1, const pair<int, char> & p2) {
                return p1.first > p2.first;
            });
            bool hasNext = false;
            for (auto & [freq, ch] : arr) {
                int m = res.size();
                if (freq <= 0) {
                    break;
                }
                if (m >= 2 && res[m - 2] == ch && res[m - 1] == ch) {
                    continue;
                }
                hasNext = true;
                res.push_back(ch);
                freq--;
                break;
            }
            if (!hasNext) {
                break;
            }
        }
      
        return res;
    }
};
  1. 石子游戏 III
    Alice 和 Bob 继续他们的石子游戏。几堆石子 排成一行 ,每堆石子都对应一个得分,由数组 stoneValue 给出。Alice 和 Bob 轮流取石子,Alice 总是先开始。在每个玩家的回合中,该玩家可以拿走剩下石子中的的前 1、2 或 3 堆石子 。比赛一直持续到所有石头都被拿走。每个玩家的最终得分为他所拿到的每堆石子的对应得分之和。每个玩家的初始分数都是 0 。比赛的目标是决出最高分,得分最高的选手将会赢得比赛,比赛也可能会出现平局。假设 Alice 和 Bob 都采取 最优策略 。如果 Alice 赢了就返回 "Alice" ,Bob 赢了就返回 "Bob",分数相同返回 "Tie" 。

本题适合用动态规划解决。状态方程主要由i + 1, i + 2, i + 3决定,先遍历一般取后缀和,然后每次按最优解操作,最后比较f[0]状态下能拿到的最大大小。

cpp 复制代码
class Solution {
public:
    string stoneGameIII(vector<int>& stoneValue) {
        int n = stoneValue.size();
        
        vector<int> suffix_sum(n);
        suffix_sum[n - 1] = stoneValue[n - 1];
        for (int i = n - 2; i >= 0; --i) {
            suffix_sum[i] = suffix_sum[i + 1] + stoneValue[i];
        }

        vector<int> f(n + 1);
        // 边界情况,当没有石子时,分数为 0
        // 为了代码的可读性,显式声明
        f[n] = 0;
        for (int i = n - 1; i >= 0; --i) {
            int bestj = f[i + 1];
            for (int j = i + 2; j <= i + 3 && j <= n; ++j) {
                bestj = min(bestj, f[j]);
            }
            f[i] = suffix_sum[i] - bestj;
        }
        
        int total = accumulate(stoneValue.begin(), stoneValue.end(), 0);
        if (f[0] * 2 == total) {
            return "Tie";
        }
        else {
            return f[0] * 2 > total ? "Alice" : "Bob";
        }
    }
};
  1. 排名靠前的旅行者
    编写解决方案,报告每个用户的旅行距离。返回的结果表单,以 travelled_distance 降序排列 ,如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列 。返回结果格式如下例所示。
sql 复制代码
# Write your MySQL query statement below
select t1.name,ifnull(sum(t2.distance),0) as travelled_distance
from Users t1
left join Rides t2
on t1.id=t2.user_id
group by t1.id,t1.name
order by travelled_distance desc,t1.name;
  1. 数组中的字符串匹配
    给你一个字符串数组 words ,数组中的每个字符串都可以看作是一个单词。请你按 任意 顺序返回 words 中是其他单词的子字符串的所有单词。
    如果你可以删除 words[j] 最左侧和/或最右侧的若干字符得到 words[i] ,那么字符串 words[i] 就是 words[j] 的一个子字符串。

暴力搜索

cpp 复制代码
class Solution {
public:
    vector<string> stringMatching(vector<string>& words) {
        vector<string> ret;
        for (int i = 0; i < words.size(); i++) {
            for (int j = 0; j < words.size(); j++) {
                if (i != j && words[j].find(words[i]) != string::npos) {
                    ret.push_back(words[i]);
                    break;
                }
            }
        }
        return ret;
    }
};
相关推荐
菌菌的快乐生活8 分钟前
理解支持向量机
算法·机器学习·支持向量机
大山同学12 分钟前
第三章线性判别函数(二)
线性代数·算法·机器学习
axxy200031 分钟前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
黑客Ash43 分钟前
安全算法基础(一)
算法·安全
m0_748245521 小时前
吉利前端、AI面试
前端·面试·职场和发展
AI莫大猫1 小时前
(6)YOLOv4算法基本原理以及和YOLOv3 的差异
算法·yolo
taoyong0012 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
Uu_05kkq2 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
清梦20203 小时前
经典问题---跳跃游戏II(贪心算法)
算法·游戏·贪心算法
Dream_Snowar3 小时前
速通Python 第四节——函数
开发语言·python·算法