在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
方法一:定义一个优先级队列,因为它的底层是大顶堆,然后弹出 k-1个元素,顶元素就是第 k 个大的 元素
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int>p(nums.begin(),nums.end());
for(int i = 0;i<k-1;++i){
p.pop();
}
return p.top();
}
方法二: 利用排序库函数
sort(nums.begin(),nums.end());
return nums[nums.size()-k];
lambda 表达式定义一个降序排序
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(),nums.end(),[](int a,int b){
return a>b;
});
return nums[k-1];
}
python 函数可以直接利用排序的库函数
# 库函数1
num = sorted(num,reverse=True);
# 库函数2
# nums.sort(reverse=True)
return num[k-1]
给定一个非空的整数数组,返回其中出现频率前 k 高的元素
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
说明:你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数
你的算法的时间复杂度必须优于 O(n*logn) , n 是数组的大小
方法一:C++ 版本
思路:先将数据本身和次数统一,放到一个 unordered_map 序列式容器中,然后把 pair
vector<int> topKFrequent(vector<int>& nums, int k) {
priority_queue<pair<int,int>>p;
vector<int>res;
unordered_map<int,int>mp;
for(auto&e: nums){
mp[e]++;
}
// 将数据导入到优先级队列中
for(auto&e: mp){
// 元素的次数作为键,元素本身的内容作为值
p.push(pair<int,int>(e.second,e.first));
}
// 删除堆第一个元素,因为第一个元素就是最大值
// 删除完之后再进行调整,将次大的值调整到堆顶
while(k--){
res.push_back(p.top().second);
p.pop();
}
return res;
}
方法二:python 版本
思路:把所有的元素组合到字典中,然后按照键值从大到小排序,键值就是某一个元素出现的次数,最后返回前 k 个元素
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
res = []
dic = {}
for i in range(len(nums)):
if nums[i] not in dic:
dic[nums[i]] = 1
else:
dic[nums[i]]+=1
# items 函数以列表返回可遍历的(键, 值) 元组数组
# 根据它的第二个值进行降序排序
dic = sorted(dic.items(),key=lambda x:x[1],reverse=True)
for key,_ in dic[:k]:
res.append(key)
return res
在大小为 2N 的数组 A 中有 N+1 个不同的元素,其中有一个元素重复了 N 次
返回重复了 N 次的那个元素
示例 1:
输入:[1,2,3,3]
输出:3
示例 2:
输入:[2,1,2,5,3,2]
输出:2
示例 3:
输入:[5,1,5,2,5,3,5,4]
输出:5
提示:
4 <= A.length <= 10000
0 <= A[i] < 10000
A.length 为偶数
思路:利用 unordered_map 结构,底层是通过哈希表来实现的,所以我们访问的时候可以以O(1)的时间快速查找
int repeatedNTimes(vector<int>& A) {
size_t N = A.size()/2;
// 用unordered_map统计每个元素出现的次数
unordered_map<int, int> m;
for(auto e : A)
m[e]++;
// 找出出现次数为N的元素
for(auto& e : m){
if(e.second == N)
return e.first;
}
return 0;
}
用 python 也是非常简单的,直接用一个字典结构就可以了
给定两个数组,编写一个函数来计算它们的交集
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
说明:
输出结果中的每个元素一定是唯一的。
我们可以不考虑输出结果的顺序
方法一 :python 版本
在遍历 nums1 的时候,查看当前元素是否在 num2 中,如果在则插入到一个列表 ,然后利用 set 函数去重
def intersection(nums1, nums2):
res = []
for i in nums1:
if i in nums2:
res.append(i)
return set(res)
方法二:C++ 版本
思路基本和 python 一致,把数据放到一个 unordered_set 关联式容器中,通过遍历 nums 1 或者 nums2 来判断是否有重叠元素
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 首先给 num1 和 nums2 去重
unordered_set<int>us1;
for(auto&e:nums1){
us1.insert(e);
}
unordered_set<int>us2;
for(auto&e:nums2){
us2.insert(e);
}
// 如果 us1 中的元素在 us2中,那么则插入到返回数组中
vector<int>res;
for(auto&e:us1){
if(us2.find(e)!=us2.end()){
res.push_back(e);
}
}
return res;
}
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
说明:
输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致(不考虑输出结果的顺序)
进阶:
如果给定的数组已经排好序呢?你将如何优化你的算法?
如果 nums1 的大小比 nums2 小很多,哪种方法更优?
如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
方法一:在 python 中有一个 & 符号可以在集合中计算交集,然后利用 count 函数计数该字符出现的次数
def intersect(nums1, nums2):
# 转换为集合,然后求出交集
inter = set(nums1) & set(nums2)
res = []
for i in inter:
res += [i] * min(nums1.count(i), nums2.count(i))
return res
方法二:在 num2 中找到一次就删除一次,这样就不用计算次数了
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
n=len(nums1)
nums=[]
for i in range(n):
if nums1[i] in nums2:
nums.append(nums1[i])
nums2.remove(nums1[i])
return nums
方法三:C++ 思路,利用 unordered_map 容器
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int> dict;
vector<int> res;
for(auto i : nums1)
dict[i]++;
for(auto j : nums2){
if(dict.count(j)){
res.push_back(j);
dict[j]--;
// 当 dict[j]==0意味着没有元素了
// 但是 count 值还会返回1,所以需要删除掉
if(dict[j] == 0)
dict.erase(j);
}
}
return res;
}
给定两个句子 A 和 B (句子是一串由空格分隔的单词。每个单词仅由小写字母组成)
如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的
返回所有不常用单词的列表,您可以按任何顺序返回列表
示例 1:
输入:A = “this apple is sweet”, B = “this apple is sour”
输出:[“sweet”,“sour”]
示例 2:
输入:A = “apple apple”, B = “banana”
输出:[“banana”]
提示:
0 <= A.length <= 200
0 <= B.length <= 200
A 和 B 都只包含空格和小写字母
方法一:输入流和输出流
根据题目意思我们不难发现,需要返回两个句子中只出现一次的单词,所以我们先把两个句子合并为一句然后转换为列表,通过字典遍历如果 value 等于 1,则把对应的 key 添加到返回列表中
vector<string> uncommonFromSentences(string A, string B) {
string str = A + " " + B;
unordered_map<string,int>mp;
string temp;
stringstream stream(str);
while(stream>>temp){
mp[temp]++;
}
vector<string>res;
for(auto i = mp.begin();i!=mp.end();++i){
if(i->second ==1){
res.push_back(i->first);
}
}
return res;
}
方法二:python 版本写起来比较简单
def uncommonFromSentences(self, A: str, B: str) -> List[str]:
dic = {}
temp = A.split() + B.split()
for s in temp:
if s not in dic:
dic[s]=1
else:
dic[s]+=1
res = []
for key,value in dic.items():
if value == 1:
res.append(key)
return res
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素
注意,它是排序后的第 k 小元素,而不是第 k 个元素
示例
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
]
k = 8
返回 13
方法一:将所有数放到一个列表中,然后对列表进行排序,最后取出第k个元素
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
res = []
#for num in matrix:
# res += num
for i in range(len(matrix)):
for j in range(len(matrix[0])):
res.append(matrix[i][j])
res.sort()
return res[k-1]
方法二:可以将数据放入一个优先级队列,然后弹出 size-k 个元素,返回队列的首元素,当然这种方法和第一种差不多
int kthSmallest(vector<vector<int>>& matrix, int k) {
priority_queue<int>pq;
for(int i = 0;i<matrix.size();++i){
for(int j = 0;j<matrix[0].size();++j){
pq.push(matrix[i][j]);
}
}
int row = matrix.size();
int col = matrix[0].size();
int n = row*col-k;
while(n--){
pq.pop();
}
return pq.top();
}
方法三:二分查找
1.找出二维矩阵中最小的数 min,最大的数 max,那么第k小的数必定在left~right之间
2.mid=(min+max) / 2;在二维矩阵中寻找小于等于 mid 的元素个数count
3.若这个 count 小于 k ,表明第 k 小的数在右半部分且不包含mid,即 min=mid+1, 又保证了第k小的数在 min ~ max之间
4.若这个 count 大于 k,表明第 k 小的数在左半部分且可能包含 mid,即 max=mid,又保证了第k小的数在 min ~ max 之间
5.因为每次循环中都保证了第 k 小的数在 min ~ max 之间,当 min == max 时,第 k 小的数即被找出,等于 min
int find(vector<vector<int>>& matrix,int mid){
int count = 0;
for(int i = 0;i<matrix.size();++i){
for(int j = 0;j<matrix[0].size();++j){
if(matrix[i][j]<=mid){
++count;
}
}
}
return count;
}
int kthSmallest(vector<vector<int>>& matrix, int k) {
int row = matrix.size();
int col = matrix[0].size();
int min = matrix[0][0];
int max = matrix[row-1][col-1];
while(min < max){
int mid = min+(max-min)/2;
int count = find(matrix,mid);
if(count<k){
min =mid+1;
}else{
max = mid;
}
}
return min;
}
给定一个字符串,请将字符串里的字符按照出现的频率降序排列
示例1
输入:
“tree”
输出:
“eert”
解释:
'e’出现两次,'r’和’t’都只出现一次。
因此’e’必须出现在’r’和’t’之前。此外,"eetr"也是一个有效的答案。
示例2
输入:
“cccaaa”
输出:
“cccaaa”
解释:
'c’和’a’都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。
示例3
输入:
“Aabb”
输出:
"bbAa
解释:
此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意’A’和’a’被认为是两种不同的字符
思路:首先对字符串s中的元素进行计数,然后根据 key 进行降序排列,但是在排列的过程中去掉了重复值,所以后面在重组字符串的时候,需要对字符出现的个数乘以字符.
from collections import Counter
def frequencySort(self, s: str) -> str:
d = Counter(s)
# 对key 进行降序的排列
res = sorted(d,key=d.get,reverse=True)
return ''.join([x*d[x] for x in res])
C++版本:利用 multimap 和 map 关联式容器,首先利用 map 对字符串进行计数和排序,然后在将数据导入到 multimap 容器中,进行输出
之所以不直接使用 multimap 容器,是因为 multimap 不支持下标访问,也没有库函数将数据直接写入到multimap中,
当数据导入到multimap 中,该容器会自动根据key值进行升序排序,key的类型是int,这正好满足题目要求
最后注意的一点是:如果是从前往后遍历 multimap容器的元素,就需要倒插入或者倒覆盖,如果是从后往前遍历,直接进行字符串的尾加操作就可以了
class Solution {
public:
string frequencySort(string s) {
for(auto&e : s){
mp[e]++;
}
for(auto p=mp.begin();p!=mp.end();p++){
multi.insert(make_pair(p->second,p->first));
}
int n = s.size()-1;
for(auto p=multi.begin();p!=multi.end();p++){
int a = p->first;
char c = p->second;
// 这里采用的是覆盖,也可以另外定义一个字符串变量返回
while(a-- >0){
s[n--] = c;
}
}
return s;
}
private:
map<char,int>mp;
multimap<int,char>multi;
};