Day 3
Leetcode 414.第三大的数
sort等内置排序函数的时间复杂度通常为O(nlongn)
.因此想要O(n)
的复杂度就不能对整个数组进行排序。
C++中
#include <unordered_set>
中的的unordered_set<int>
集合可以用于去重。- 使用
std::sort
(默认升序)结合仿函数std::greater<int>()
可进行降序排序。如std::sort(numsNoRepeat.begin(), numsNoRepeat.end(), std::greater<int>());
#include <climits>
中的INT_MIN
表示int
类型的最小可能值。这个值通常是 -2147483648(在大多数32位和64位系统上),对应于二进制补码表示的最小整数值。 常被用作初始值来查找最大值,因为任何有效的整数都会比INT_MIN
大。- size_t:无符号整数,安全,防止负值错误
- 表示内存大小:当你需要表示一个对象的大小(比如通过
sizeof
操作符获得的结果)时,size_t
是返回类型。 - 数组索引:在数组操作中,
size_t
常用于表示数组的索引,因为它保证是非负的。 - 内存分配:在使用动态内存分配函数(如
malloc
)时,size_t
被用来表示要分配的字节数。
- 表示内存大小:当你需要表示一个对象的大小(比如通过
#include <vector>
#include <unordered_set>
#include <algorithm>
class Solution {
public:
int thirdMax(std::vector<int>& nums) {
std::unordered_set<int> uniqueNums(nums.begin(), nums.end());
std::vector<int> numsNoRepeat(uniqueNums.begin(), uniqueNums.end());
if (numsNoRepeat.size() < 3) {
int max = INT_MIN;
for (int num : nums) {
max = std::max(max, num);
}
return max;
}
std::sort(numsNoRepeat.begin(), numsNoRepeat.gegin()+3, std::greater<int>());
int first = numsNoRepeat[0];
int second = numsNoRepeat[1];
int third = numsNoRepeat[2];
for (size_t i = 3; i < numsNoRepeat.size(); ++i) {
int num = numsNoRepeat[i];
if (num > first) {
third = second;
second = first;
first = num;
} else if (second < num && num < first) {
third = second;
second = num;
} else if (third < num && num < second) {
third = num;
}
}
return third;
}
};
Python中
set()
函数可用于去重sorted()
函数可用于排序。且与列表的sort()
方法不同,sorted()
不会对原始列表进行修改,而是返回一个新的排序后的列表。
class Solution:
def thirdMax(self, nums: List[int]) -> int:
nums_no_repeat = list(set(nums))# 使用set()去除重复元素
if len(nums_no_repeat) < 3: # 若去重后的列表长度小于3,返回最大元素
return max(nums)
# 找到去重列表前三个数中的第一、第二、第三大的数
first, second, third = sorted(nums_no_repeat[0:3], reverse = 1)
for num in nums_no_repeat[3:]: # 从第四位开始,遍历去重列表
if num > first: # 若num大于第一大的数,则:
third = second # 修改第三大的数为原来第二大的数
second = first # 修改第二大的数为原来第一大的数
first = num # 修改第一大的数为num
elif second < num < first: # 若num位于第一大的数和第二大的数之间,则:
third = second # 修改第三大的数为原来第二大的数
second = num # 修改第二大的数为num
elif third < num < second: # 若num位于第二大的数和第三大的数之间,则:
third = num # 修改第三大的数为num
return third # 遍历结束,返回第三大的数
Leetcode 1518. 换水问题
模拟方法
记一开始有 b 瓶水,e 个空瓶换一瓶水。
两种迭代思路:
- 首先我们一定可以喝到 b 瓶酒,剩下 b 个空瓶。接下来我们可以拿瓶子换酒,每次拿出 e 个瓶子换一瓶酒,然后再喝完这瓶酒,得到一个空瓶。以此类推,我们可以统计得到答案。
class Solution {
public:
int numWaterBottles(int numBottles, int numExchange) {
int bottle = numBottles, ans = numBottles;
while (bottle >= numExchange) {
bottle -= numExchange;
++ans;
++bottle;
}
return ans;
}
};
-
首先我们一定可以喝到 b 瓶酒,剩下 b 个空瓶。接下来每次拿出所有能换的瓶子换n瓶水,以此类推。
class Solution: def numWaterBottles(self, numBottles: int, numExchange: int) -> int: # 初始化条件 emp_bottle = numBottles ans = numBottles while(emp_bottle >= numExchange): n = emp_bottle // numExchange # 每换一次多喝到的瓶数 ans += n emp_bottle = n + (emp_bottle%numExchange) # 换完并喝完后剩余的总空瓶数 return ans
Leetcode 877. 石子游戏
这道题是「486. 预测赢家」的特例。和第 486 题相比,这道题增加了两个限制条件:
- 数组的长度是偶数;
- 数组的元素之和是奇数,所以没有平局。
还没学动态规划前,掌握数学解法即可。
数学解法思路:有偶数堆石子,可以将石子堆分为奇数堆和偶数堆,经过几次模拟可以发现,作为先手方总可以只取奇数堆或者偶数堆,那么只需要先计算好奇数堆还是偶数堆的总和大,那么取对应的那组即可。因此先手必胜。