目录
- 1.LeetCode:349. 两个数组的交集
- 2.LeetCode:面试题 02.02. 返回倒数第 k 个节点
- 3.LeetCode:面试题 02.03. 删除中间节点
- 4.LeetCode:83. 删除排序链表中的重复元素
- 5.LeetCode:202. 快乐数
- 6.LeetCode:面试题56 - I. 数组中数字出现的次数
- 7.LeetCode:53. 最大子序和
- 8.LeetCode:50. Pow(x, n)
- 9.LeetCode:面试题03. 数组中重复的数字
- 10.LeetCode:面试题05. 替换空格
- 11.LeetCode:面试题04. 二维数组中的查找
- 12.LeetCode:面试题06. 从尾到头打印链表
- 13.LeetCode:面试题22. 链表中倒数第k个节点(和2重了)
- 14.LeetCode:面试题 02.01. 移除重复节点
- 15.LeetCode:680. 验证回文字符串 Ⅱ
- 16.LeetCode:面试题 01.04. 回文排列
- 17.LeetCode:1371.每个元音包含偶数次的最长子字符串(好题,值得思考)
- 18.LeetCode:面试题15. 二进制中1的个数
- 19.LeetCode:461. 汉明距离
- 20.LeetCode:11.盛最多水的容器
- 21.LeetCode:198. 打家劫舍
- 22.LeetCode:19.删除链表的倒数第N个节点
- 23.LeetCode:1431.拥有最多糖果的孩子
- 24.LeetCode:面试题64. 求1+2+…+n
- 25.LeetCode:238.除自身以外数组的乘积
- 26.LeetCode:面试题29. 顺时针打印矩阵
- 27.LeetCode:990.等式方程的可满足性
- 28.LeetCode:面试题46. 把数字翻译成字符串
- 29.LeetCode:14. 最长公共前缀
- 30.LeetCode:剑指 Offer 09. 用两个栈实现队列
- 31.LeetCode:108.将有序数组转换为二叉搜索树
- 32.LeetCode:32.最长有效括号
- 33.LeetCode:112.路径总和-递归
- 34.LeetCode:面试题 16.11. 跳水板
- 35.LeetCode:剑指 Offer 28. 对称的二叉树-递归
- 36.LeetCode:174.地下城游戏-DP
- 37.LeetCode:20. 三角形最小路径和-DP
- 38.LeetCode:64.最小路径和-DP
- 39.LeetCode:1025.除数博弈
- 40.LeetCode:100.相同的树-DFS或BFS
- 41.LeetCode:337. 打家劫舍 III-递归+dp
- 42.LeetCode:696. 计数二进制子串
- 43.LeetCode:剑指 Offer 57 - II. 和为s的连续正数序列-滑动窗口
- 44.LeetCode:733.图像渲染-DFS或BFS
- 45.LeetCode:109. 有序链表转换二叉搜索树-快慢指针和递归
- 46.LeetCode:647.回文子串-中心拓展
- 47.LeetCode:剑指 Offer 39. 数组中出现次数超过一半的数字-投票
- 48.LeetCode:剑指 Offer 66.构建乘积数组
- 49.LeetCode:486. 预测赢家
- 50.LeetCode:347. 前 K 个高频元素-map+pair
1.LeetCode:349. 两个数组的交集
时间:20200426
题目
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
说明:
输出结果中的每个元素一定是唯一的。
我们可以不考虑输出结果的顺序。
代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> m(nums1.begin(), nums1.end()); 将第一个数组的元素建立一个unordered_set
vector<int> res; //建立关于结果的vector
for(int a:nums2)
{
if(m.erase(a)) //既查找了m中是否存在a,又完成了删除a的工作,避免后续过程重复元素
{
res.push_back(a); //在vector res的末尾加入a
}
}
return res;
}
};
思路
建立一个set存第一个vector的值,去遍历第二个vector。一开始是使用的map实现。
2.LeetCode:面试题 02.02. 返回倒数第 k 个节点
时间:20200429
题目
面试题 02.02. 返回倒数第 k 个节点
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
注意:本题相对原题稍作改动
示例:
输入: 1->2->3->4->5 和 k = 2
输出: 4
说明:
给定的 k 保证是有效的。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
struct ListNode *slow=head;
struct ListNode *fast=head;
int fast_flag=1,slow_flag=1;
int result=0;
while(fast!=NULL)
{
fast=fast->next;
fast_flag++;
if(fast_flag-slow_flag==k)
{
result=slow->val;
slow=slow->next;
slow_flag++;
}
}
return result;
}
};
自己写的有些冗余。参考
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
if(head->next == NULL) return head->val;
ListNode *slow = head, *fast = head;
while(k--){
fast = fast->next;
}
while(fast){
slow = slow->next;
fast = fast->next;
}
return slow->val;
}
};
思路
快慢指针,快的先走,走K次。慢的开始走,最后快的指向NULL,慢的指向倒数第K个。
3.LeetCode:面试题 02.03. 删除中间节点
时间:20200429
题目
面试题 02.03. 删除中间节点
实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点。
示例:
输入:单向链表a->b->c->d->e->f中的节点c
结果:不返回任何数据,但该链表变为a->b->d->e->f
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val=node->next->val;
struct ListNode* p=node->next;
node->next=node->next->next;
delete p;
}
};
思路
这里只能访问当前节点,只能先将next节点的值赋值给当前结点, 再把next节点干掉。
4.LeetCode:83. 删除排序链表中的重复元素
时间:20200429
题目
83.删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
struct ListNode * p=head;
if(p==NULL)
return head;
while(p->next!=NULL)
{
if(p->val==p->next->val){
struct ListNode * temp =p->next;
p->next=p->next->next;
delete temp;
}
else
p=p->next;
}
return head;
}
};
思路
记得删除重复的节点。
5.LeetCode:202. 快乐数
时间:20200430
题目
202.快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
代码
class Solution {
public:
bool isHappy(int n) {
int sum=0;
int loop=n;
int count=100;
while(n!=1)
{
while(n!=0)
{
int temp=0;
temp=n%10;
sum+=temp*temp;
n/=10;
}
count--;
if(count==0)
{
return false;
}
n=sum;
sum=0;
}
return true;
}
};
思路
开始没想好无限循环的处理方法。后面加入一个计数,如果这个数都成0了,还没有算完,应该是进入循环了。
看了题解应该可以用快慢指针,哈希表等方法。(后面有时间再看)
6.LeetCode:面试题56 - I. 数组中数字出现的次数
时间:20200430
题目
面试题56 - I. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums <= 10000
代码
不满足空间复杂度
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
map<int,int>num_map;
for(int i:nums)
{
num_map[i]++;
}
vector<int>res;
for(int i=0;i<nums.size();i++)
{
if(num_map[nums[i]]==1)
{
res.push_back(nums[i]);
}
}
return res;
}
};
题解
class Solution {
public:
//输入: [1,2,1,3,2,5]
//输出: [3,5]
vector<int> singleNumbers(vector<int>& nums) {
int s = 0;
for (int num : nums) {
s ^= num;
}
//s是只出现一次的2个数字的^ 记做数字a,b
//既然a,b 不一样,那么s肯定不是0,那么s的二进制肯定至少有1位(第n位)是1,只有0^1才等于1
//所以a,b 在第n位,要么a是0,b是1 ,要么b是0,a是1 ---->A
//s = 3 ^ 5; 0011 ^ 0101 = 0110 = 6
//假设int是8位
//-6 原码1000 0110
// 反码1111 1001
// 补码1111 1010
//s & (-s)
// 0000 0110
//& 1111 1010
// 0000 0010
//所以k = s & (-s) 就是保留s的最后一个1,并且将其他位变为0 也就是s最后一个1是倒数第二位 --->B
//由于s & (-s)很方便找到一个1 所以用他了,其实找到任何一个1都可以
//根据A和B 我们可以确定 3 和 5 必定可以分到 不同的组里
//同理 1和1 由于二进制完全相同,所有必定分到相同的组里
//同理 2和2 由于二进制完全相同,所有必定分到相同的组里
int k = s & (-s);
//1 0001 第一组
//2 0010 第二组
//1 0001 第一组
//3 0011 第二组
//2 0010 第二组
//5 0101 第一组
//第一组 1 1 5 第二组 2 3 2 这样我们就将2个只有一个的数 分到了2个数组里了
vector<int> rs(2,0);
for(int num : nums){
if(num & k){
//第二组
rs[0] ^= num;
}else{
//第一组
rs[1] ^= num;
}
}
return rs;
}
};
思路
使用map操作,遍历数组,val为1,将其放入vector中。
关于位操作确实不太熟练。大致思路,每个数都进行异或操作,得到的s就是只出现一次的两个数的异或结果。然后s&(-s),这里涉及到求负数的补码,保留s的最后一个1,并且将其他位变为0。然后和原数组进行异或操作。
正数的反码补码都一样,负数用补码表示,其补码等于取反+1
7.LeetCode:53. 最大子序和
时间:20200502
题目
53.最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
代码
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size() == 0) return NULL;
int res = INT_MIN;
int sum = -1;
for(int i = 0; i < nums.size(); ++i)
{
sum = max(nums[i], sum + nums[i]);
res = max(sum, res);
}
return res;
}
};
思路
动态规划(之前做过的都没写出来)
8.LeetCode:50. Pow(x, n)
时间:20200511
题目
50.Pow(x, n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−2^31 ,2^31 − 1] 。
代码
class Solution {
public:
double myPow(double x, long long n) {
if (n == 0)
return 1;
if (n == 1)
return x;
if (n < 0)
return 1.0 / myPow(x, -n);
if (n % 2 == 1)
return x * myPow(x, n - 1);
else {
double cur = myPow(x, n / 2);
return cur * cur;
}
}
};
思路
用循环的方法会超时,同时n=-2^31(-2147483648),直接取相反数会溢出。
递归
主要是注意n的正负,这个题比较简单了,直接递归调用就行。
如果 n 是负数,那么相当于求 (1/x)^(-n)。
如果 n 是正数 且 奇数,那么结果需要单独乘以 x
如果 n 是正数 且 偶数,求(x2)(n/2),一直递归下去即可。
9.LeetCode:面试题03. 数组中重复的数字
时间:20200516
题目
面试题03. 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
代码
1.排序
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
nums.push_back(nums.size());
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++)
{
if(i+1<=nums.size()&&nums[i]==nums[i+1])
return nums[i];
}
return 0;
}
};
2.哈希表
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
map<int,int>dic;
for(auto i:nums)
{
dic[i]++;
if(dic[i]>1)
return i;
}
return 0;
}
};
思路
1.排序后找重复的比较容易,这里额外再最后加了一位N,防止越界。
2.哈希表,key-value,如果值大于1就重复了。
10.LeetCode:面试题05. 替换空格
时间:20200516
题目
面试题05. 替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
限制:
0 <= s 的长度 <= 10000
代码
class Solution {
public:
string replaceSpace(string s) {
string res;
for(int i=0;i<s.size();i++)
{
if(s[i]==' ')
{
res+="%20";
continue;
}
res+=s[i];
}
return res;
}
};
思路
利用C++中string的特性
11.LeetCode:面试题04. 二维数组中的查找
时间:20200517
题目
面试题04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
限制:
0 <= n <= 1000
0 <= m <= 1000
代码
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
if(matrix.empty())
return false;
int rows=matrix.size();
int cols=matrix[0].size();
if( rows>0 && cols>0)
{
int row=0;
int col=cols-1;
while(col>=0&&row<rows)
{
if(matrix[row][col]==target)
{
return true;
}
else if(matrix[row][col]>target)
{
--col;
}
else if(matrix[row][col]<target)
{
++row;
}
}
}
return false;
}
};
思路
剑指offer题目,缩小范围的思想。从右上角数开始,分为三种情况:1.等于,查找结束;2.target更大,剔除所在列;3.target更小,剔除所在行。
当然也可以遍历整个二维数组。
12.LeetCode:面试题06. 从尾到头打印链表
时间:20200517
题目
面试题06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> res;
vector<int> reversePrint(ListNode* head) {
//方法1:reverse反转法
while(head){
res.push_back(head->val);
head = head->next;
}
//使用algorithm算法中的reverse反转res
reverse(res.begin(),res.end());
return res;
//方法2:入栈法
/*
stack<int> s;
//入栈
while(head){
s.push(head->val);
head = head->next;
}
//出栈
while(!s.empty()){
res.push_back(s.top());
s.pop();
}
return res;
*/
//方法3:递归
/*
if(head == nullptr)
return res;
reversePrint(head->next);
res.push_back(head->val);
return res;
*/
//方法4:改变链表结构
/*
ListNode *pre = nullptr;
ListNode *next = head;
ListNode *cur = head;
while(cur){
next = cur->next;//保存当前结点的下一个节点
cur->next = pre;//当前结点指向前一个节点,反向改变指针
pre = cur;//更新前一个节点
cur = next;//更新当前结点
}
while(pre){//上一个while循环结束后,pre指向新的链表头
res.push_back(pre->val);
pre = pre->next;
}
return res;
}
*/
};
思路
只想到第一、二种方法。
13.LeetCode:面试题22. 链表中倒数第k个节点(和2重了)
时间:20200518
题目
面试题22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
struct ListNode * p=head;
struct ListNode * q=head;
while(p)
{
if(k>0)
{
p=p->next;
k--;
}
else
{
p=p->next;
q=q->next;
}
}
return q;
}
};
思路
双指针
14.LeetCode:面试题 02.01. 移除重复节点
时间:20200518
题目
面试题 02.01. 移除重复节点
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
示例2:
输入:[1, 1, 1, 1, 2]
输出:[1, 2]
提示:
链表长度在[0, 20000]范围内。
链表元素在[0, 20000]范围内。
进阶:
如果不得使用临时缓冲区,该怎么解决?
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeDuplicateNodes(ListNode* head) {
vector<int>temp;
struct ListNode * p=head;
struct ListNode * res=head;
while(head)
{
temp.push_back(head->val);
head=head->next;
if(head==NULL)
{
break;
}
for(int i=0;i<temp.size();i++)
{
while(head!=NULL&&head->val==temp[i])
{
head=head->next;
i=0;
}
}
p->next=head;
p=head;
}
return res;
}
};
思路
用了一个数组,每移动一个节点都去找有没有出现相同的数字,如果出现则跳过,但是要将i=0。做麻烦了,可以用集合或者哈希表,会更简单。(后期在来看)
15.LeetCode:680. 验证回文字符串 Ⅱ
时间:20200519
题目
- 验证回文字符串 Ⅱ
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: “aba”
输出: True
示例 2:
输入: “abca”
输出: True
解释: 你可以删除c字符。
注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
代码
class Solution {
public:
bool checkPalindrome(const string &s,int low,int high)
{
for(int i=low,j=high;i<j;i++,j--)
{
if(s[i]!=s[j])
return false;
}
return true;
}
bool validPalindrome(string s) {
int low=0;
int high=s.size()-1;
while(low<high)
{
char c1=s[low],c2=s[high];
if(c1==c2)
{
low++;
high--;
}
else
{
return checkPalindrome(s,low,high-1) || checkPalindrome(s,low+1,high);
}
}
return true;
}
};
思路
16.LeetCode:面试题 01.04. 回文排列
时间:20200520
题目
面试题 01.04. 回文排列
给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。
回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。
回文串不一定是字典当中的单词。
示例1:
输入:“tactcoa”
输出:true(排列有"tacocat"、“atcocta”,等等)
代码
class Solution {
public:
bool canPermutePalindrome(string s) {
map<char,int>letter_map;
for(auto &i:s)
{
letter_map[i]++;
}
int count=0;
for(auto i:letter_map)
{
if(i.second%2!=0)
{
count++;
}
}
if(count>1)
return false;
else
return true;
}
};
思路
统计次数。s.size()为偶数,则count=0;s.size()为奇数,则count=1。
17.LeetCode:1371.每个元音包含偶数次的最长子字符串(好题,值得思考)
时间:20200520
题目
1371.每个元音包含偶数次的最长子字符串
给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。
示例 1:
输入:s = “eleetminicoworoep”
输出:13
解释:最长子字符串是 “leetminicowor” ,它包含 e,i,o 各 2 个,以及 0 个 a,u 。
示例 2:
输入:s = “leetcodeisgreat”
输出:5
解释:最长子字符串是 “leetc” ,其中包含 2 个 e 。
示例 3:
输入:s = “bcbcbc”
输出:6
解释:这个示例中,字符串 “bcbcbc” 本身就是最长的,因为所有的元音 a,e,i,o,u 都出现了 0 次。
提示:
1 <= s.length <= 5 x 10^5
s 只包含小写英文字母。
代码
class Solution {
public:
int findTheLongestSubstring(string s) {
int ans = 0, status = 0, n = s.size();
vector<int> pos(32, -1);
pos[0] = 0;
for (int i = 0; i < n; i ++) {
if (s[i] == 'a') {
status ^= 1<<0;
} else if (s[i] == 'e') {
status ^= 1<<1;
} else if (s[i] == 'i') {
status ^= 1<<2;
} else if (s[i] == 'o') {
status ^= 1<<3;
} else if (s[i] == 'u') {
status ^= 1<<4;
}
if (pos[status] != -1) {
ans = max(ans, i + 1 - pos[status]);
} else {
pos[status] = i + 1;
}
}
return ans;
}
};
思路
好题,值得思考。借用大佬的思路(侵删)
思路描述:官方题解的 前缀和+状态压缩 是真的没想到,这里稍微做个解释吧,
首先题目中要求子字符串中每个元音字母恰好出现偶数次,我们就可以使用 0 和 1 来标识每个字母的状态(偶数次或奇数次),我们不需要知道每个字母出现的完整次数,只需要知道这个次数的奇偶性
那么我们可以注意到奇数次 + 1 = 偶数次,偶数次 + 1 = 奇数次,所以我们可以使用 异或 来参与运算: 比如 aba
初始时 status = 00000,然后到 a 的时候 00000 ^ 00001 = 00001,1 说明 a 出现奇数次
然后到 b 的时候 00001 ^ 00010 = 00011,两个 1 说明 a、b 都出现奇数次
最后到 a 的时候 00011 ^ 00001 = 00010,说明只有 b 出现奇数次了。
以上也说明我们确实是可以使用状态码去标识每个元音字母出现次数的奇偶性。
那么我们怎么去统计最长子串的长度呢?
首先我们先盘盘哪些子串符合要求,因为现在每个下标对应的状态码其实也就只有 0 和 1
如果坐标 i 对应的状态码是 00011,坐标 j 对应的状态码是 00011,那么他们俩中间的元音字母数一定是偶数,如果某一位不相同,那么绝对不可能是偶数,因为偶数-奇数=奇数,奇数-偶数=奇数
所以我们每次求出一个坐标的状态码的时候就去瞅瞅这个状态码前面是否存在,如果存在,那么就计算一下之间子字符串的长度就 ok 了,那么我们还需要啥?明显需要一个hash表,存储每个状态码对应的下标!当然因为我们状态码最长也就是 11111 = 2^5 - 1 = 31,开一个 32 大小的数组就好了。
因为是学习官方题解写的,代码也差不多,这个代码确实是比较简洁清晰的,也没必要去复盘。
18.LeetCode:面试题15. 二进制中1的个数
时间:20200523
题目
面试题15. 二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
代码
方法一:
如果n是负数去移动N的话,容易进入死循环。
移动前是负数,移动后也是负数。最高位是1,一直右移容易出问题。
class Solution {
public:
int hammingWeight(uint32_t n) {
unsigned int temp=1;
int res=0;
while(temp)
{
if(temp&n){
res++;
}
temp=temp << 1;
}
return res;
}
};
方法二:(官方)
n=n&(n-1)直接消去末位的1(相当于把整数最右边一个1变为0)
class Solution {
public:
int hammingWeight(uint32_t n) {
int res=0;
while(n)
{
res++;
n=n&(n-1);
}
return res;
}
};
思路
19.LeetCode:461. 汉明距离
时间:20200523
题目
- 汉明距离
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。
注意:
0 ≤ x, y < 231.
示例:
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
上面的箭头指出了对应二进制位不同的位置。
代码
class Solution {
public:
int hammingDistance(int x, int y) {
int res=0;
int count=0;
res=x^y;
while(res)
{
count++;
res=res&(res-1);
}
return count;
}
};
思路
做一个异或,然后用上一题统计1的个数。
20.LeetCode:11.盛最多水的容器
时间:20200527
题目
11.盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
代码
class Solution {
public:
int maxArea(vector<int>& height) {
int res=0;
int left=0,right=height.size()-1;
while(left<right)
{
res=max(res,min(height[left],height[right])*(right-left));
if(height[left]<height[right])
left++;
else
right--;
}
return res;
}
};
思路
暴力法会超时,双指针,一头一尾,小的那方移动。
21.LeetCode:198. 打家劫舍
时间:20200529
题目
198.打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
代码
class Solution {
public:
int rob(vector<int>& nums) {
int length=nums.size();
vector<int>dp(length,0);
if(length<1)
return 0;
else if(length==1)
return nums[0];
else if(length==2)
return max(nums[0],nums[1]);
else
{
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<length;i++)
{
dp[i]=max(dp[i-1],nums[i]+dp[i-2]);
}
}
return dp[length-1];
}
};
思路
动态规划,按摩师和小偷是一样的题。主要是找到方程:dp[i]=max(dp[i-1],nums[i]+dp[i-2])。
22.LeetCode:19.删除链表的倒数第N个节点
时间:20200529
题目
19.删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(head==NULL||head->next==NULL)
return NULL;
ListNode* slow=head;
ListNode* fast=head;
while(n)
{
fast=fast->next;
n--;
}
if(!fast)
return head->next;
while(fast->next)
{
fast=fast->next;
slow=slow->next;
}
slow->next=slow->next->next;
return head;
}
};
思路
双指针,注意一些小细节
23.LeetCode:1431.拥有最多糖果的孩子
时间:20200601
题目
1431.拥有最多糖果的孩子
给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。
对每一个孩子,检查是否存在一种方案,将额外的 extraCandies 个糖果分配给孩子们之后,此孩子有 最多 的糖果。注意,允许有多个孩子同时拥有 最多 的糖果数目。
示例 1:
输入:candies = [2,3,5,1,3], extraCandies = 3
输出:[true,true,true,false,true]
解释:
孩子 1 有 2 个糖果,如果他得到所有额外的糖果(3个),那么他总共有 5 个糖果,他将成为拥有最多糖果的孩子。
孩子 2 有 3 个糖果,如果他得到至少 2 个额外糖果,那么他将成为拥有最多糖果的孩子。
孩子 3 有 5 个糖果,他已经是拥有最多糖果的孩子。
孩子 4 有 1 个糖果,即使他得到所有额外的糖果,他也只有 4 个糖果,无法成为拥有糖果最多的孩子。
孩子 5 有 3 个糖果,如果他得到至少 2 个额外糖果,那么他将成为拥有最多糖果的孩子。
示例 2:
输入:candies = [4,2,1,1,2], extraCandies = 1
输出:[true,false,false,false,false]
解释:只有 1 个额外糖果,所以不管额外糖果给谁,只有孩子 1 可以成为拥有糖果最多的孩子。
示例 3:
输入:candies = [12,1,12], extraCandies = 10
输出:[true,false,true]
提示:
2 <= candies.length <= 100
1 <= candies[i] <= 100
1 <= extraCandies <= 50
代码
class Solution {
public:
vector<bool> kidsWithCandies(vector<int>& candies, int extraCandies) {
int vec_max=0;
vector<bool> res;
for(int i=0;i<candies.size();i++)
{
vec_max=max(vec_max,candies[i]);
}
for(int i=0;i<candies.size();i++)
{
if(candies[i]+extraCandies>=vec_max)
res.push_back(true);
else
res.push_back(false);
}
return res;
}
};
官方
class Solution {
public:
vector<bool> kidsWithCandies(vector<int>& candies, int extraCandies) {
int n = candies.size();
int maxCandies = *max_element(candies.begin(), candies.end());
vector<bool> ret;
for (int i = 0; i < n; ++i) {
ret.push_back(candies[i] + extraCandies >= maxCandies);
}
return ret;
}
};
思路
题目很简单,和官方一样的想法,哈哈。时间复杂度O(N)。
24.LeetCode:面试题64. 求1+2+…+n
时间:20200602
题目
面试题64.求1+2+…+n
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例 1:
输入: n = 3
输出: 6
示例 2:
输入: n = 9
输出: 45
限制:
1 <= n <= 10000
代码
class Solution {
public:
int sumNums(int n) {
if(n==1)
return 1;
else
return sumNums(--n)+n+1;
}
};
思路
递归
25.LeetCode:238.除自身以外数组的乘积
时间:20200604
题目
238.除自身以外数组的乘积
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
代码
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length=nums.size();
vector<int>L(length,1);
vector<int>R(length,1);
for(int i=1;i<nums.size();++i)
{
L[i]=L[i-1]*nums[i-1];
}
for(int j=length-2;j>=0;--j)
{
R[j]=R[j+1]*nums[j+1];
}
for(int k=0;k<nums.size();++k)
{
nums[k]=L[k]*R[k];
}
return nums;
}
};
思路
乘积 = 当前数左边的乘积 * 当前数右边的乘积
算法
1.初始化两个空数组 L 和 R。对于给定索引 i,L[i] 代表的是 i 左侧所有数字的乘积,R[i] 代表的是 i 右侧所有数字的乘积。
2.我们需要用两个循环来填充 L 和 R 数组的值。对于数组 L,L[0] 应该是 1,因为第一个元素的左边没有元素。对于其他元素:L[i] = L[i-1] * nums[i-1]。
3.同理,对于数组 R,R[length-1] 应为 1。length 指的是输入数组的大小。其他元素:R[i] = R[i+1] * nums[i+1]。
4.当 R 和 L 数组填充完成,我们只需要在输入数组上迭代,且索引 i 处的值为:L[i] * R[i]。
26.LeetCode:面试题29. 顺时针打印矩阵
时间:20200605
题目
面试题29. 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
限制:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100
代码
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int>res;
if(matrix.empty()) return res;
int bottom=matrix.size()-1;
int right=matrix[0].size()-1;
int top=0;
int left=0;
while(1)
{
//从左到右
for(int i=left;i<=right;++i)
res.push_back(matrix[top][i]);
if(++top>bottom)
break;
//从上到下
for(int i=top;i<=bottom;++i)
res.push_back(matrix[i][right]);
if(--right<left)
break;
//从右到左
for(int i=right;i>=left;--i)
res.push_back(matrix[bottom][i]);
if(--bottom<top)
break;
//从下到上
for(int i=bottom;i>=top;--i)
res.push_back(matrix[i][left]);
if(++left>right)
break;
}
return res;
}
};
思路
主要是画图,边界条件比较难。不应该是简单题吧。
27.LeetCode:990.等式方程的可满足性
时间:20200608
题目
990.等式方程的可满足性
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a= =b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
示例 1:
输入:[“a= =b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
示例 2:
输出:[“b= =a”,“a==b”]
输入:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
示例 3:
输入:[“a= =b”,“b= =c”,“a= =c”]
输出:true
示例 4:
输入:[“a= =b”,“b!=c”,“c= =a”]
输出:false
示例 5:
输入:[“c= =c”,“b= =d”,“x!=z”]
输出:true
提示:
1 <= equations.length <= 500
equations[i].length == 4
equations[i][0] 和 equations[i][3] 是小写字母
equations[i][1] 要么是 ‘=’,要么是 ‘!’
equations[i][2] 是 ‘=’
代码
class Solution {
public:
int letter[26];
int find(int i)
{
while(i!=letter[i])
{
letter[i]=letter[letter[i]];
i=letter[i];
}
return i;
}
bool equationsPossible(vector<string>& equations) {
for(int i=0;i<26;++i)
letter[i]=i;
for(int i=0;i<equations.size();++i)
{
if(equations[i][1]=='=')
{
int f1=find(equations[i][0]-'a');
int f2=find(equations[i][3]-'a');
if(f1!=f2) letter[f1]=f2;
}
}
for(int j=0;j<equations.size();++j)
{
if(equations[j][1]=='!')
{
int f1=find(equations[j][0]-'a');
int f2=find(equations[j][3]-'a');
if(f1==f2) return false;
}
}
return true;
}
};
思路
https://blog.csdn.net/liujian20150808/article/details/50848646
28.LeetCode:面试题46. 把数字翻译成字符串
时间:20200609
题目
面试题46. 把数字翻译成字符串
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
提示:
0 <= num < 231
代码
class Solution {
public:
int translateNum(int num) {
string val=to_string(num);
vector<int> dp(val.size()+1,0);
dp[0]=1,dp[1]=1;
for(int i=2;i<=val.size();++i)
{
if(val[i-2]=='0'||val.substr(i-2,2)>="26")
dp[i]=dp[i-1];
else
dp[i]=dp[i-1]+dp[i-2];
}
return dp[val.size()];
}
};
思路
看的题解,用的是动态规划
29.LeetCode:14. 最长公共前缀
时间:20200615
题目
- 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。
代码
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
int min_length=INT_MAX;
int pos=-1;
for(int i=0;i<strs.size();++i)
{
if(strs[i].size()<min_length){
min_length=strs[i].size();
pos=i;
}
}
string res;
if(pos==-1)
return "";
else
res=strs[pos];
for(int i=0;i<res.size();++i)
{
char temp=res[i];
for(int j=0;j<strs.size();++j)
{
if(temp!=strs[j][i])
{
res=res.substr(0,i);
break;
}
}
}
return res;
}
};
思路
自己写出来,不容易啊。简单来说就是先找到长度最小的str,以它作为标准,去一个个的比对。一旦发现不相同就用res.substr(0,i)。
30.LeetCode:剑指 Offer 09. 用两个栈实现队列
时间:20200630
题目
剑指 Offer 09. 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
示例 1:
输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:
输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用
代码
class CQueue {
public:
stack<int>s1;
stack<int>s2;
CQueue() {
}
void appendTail(int value) {
s1.push(value);
}
int deleteHead() {
if(s1.empty()&&s2.empty())
{
return -1;
}
else if(!s1.empty()&&s2.empty())
{
while(!s1.empty())
{
int temp=s1.top();
s1.pop();
s2.push(temp);
}
}
int res=s2.top();
s2.pop();
return res;
}
};
/**
* Your CQueue object will be instantiated and called as such:
* CQueue* obj = new CQueue();
* obj->appendTail(value);
* int param_2 = obj->deleteHead();
*/
思路
第一个栈支持插入操作,第二个栈支持删除操作。
31.LeetCode:108.将有序数组转换为二叉搜索树
时间:20200703
题目
108.将有序数组转换为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* insert(vector<int>& nums,int left,int right)
{
if(left>right)
return NULL;
int mid=(left+right)/2;
TreeNode *root=new TreeNode(nums[mid]);
root->left=insert(nums,left,mid-1);
root->right=insert(nums,mid+1,right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return insert(nums,0,nums.size()-1);
}
};
思路
二叉搜索树的中序遍历是升序序列,题目给定的数组是按照升序排序的有序数组,因此可以确保数组是二叉搜索树的中序遍历序列。
32.LeetCode:32.最长有效括号
时间:20200704
题目
32.最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
代码
class Solution {
public:
int longestValidParentheses(string s) {
int length=s.size();
if(length<=1)
return 0;
int res=0;
stack<int>Parenthes;
Parenthes.push(-1);
for(int i=0;i<length;++i)
{
if(s[i]=='(')
Parenthes.push(i);
else
{
Parenthes.pop();
if(Parenthes.empty())
{
Parenthes.push(i);
}
else
res=max(res,i-Parenthes.top());
}
}
return res;
}
};
思路
看到括号往栈想。
始终保持栈底元素为当前已经遍历过的元素中「最后一个没有被匹配的右括号的下标」,这样的做法主要是考虑了边界条件的处理,栈里其他元素维护左括号的下标:
对于遇到的每个 \text{‘(’}‘(’ ,我们将它的下标放入栈中
对于遇到的每个 \text{‘)’}‘)’ ,我们先弹出栈顶元素表示匹配了当前右括号:
如果栈为空,说明当前的右括号为没有被匹配的右括号,我们将其下标放入栈中来更新我们之前提到的「最后一个没有被匹配的右括号的下标」
如果栈不为空,当前右括号的下标减去栈顶元素即为「以该右括号为结尾的最长有效括号的长度」
我们从前往后遍历字符串并更新答案即可。
需要注意的是,如果一开始栈为空,第一个字符为左括号的时候我们会将其放入栈中,这样就不满足提及的「最后一个没有被匹配的右括号的下标」,为了保持统一,我们在一开始的时候往栈中放入一个值为 -1−1 的元素。
理解-1的含义
33.LeetCode:112.路径总和-递归
时间:20200704
题目
112.路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool hasPathSum(TreeNode* root, int sum) {
if(root==NULL)
return false;
if(!root->left&&!root->right)
{
return root->val==sum;
}
return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
}
};
思路
递归真是看得懂,写不出啊
34.LeetCode:面试题 16.11. 跳水板
时间:20200708
题目
面试题 16.11. 跳水板
你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。
返回的长度需要从小到大排列。
示例:
输入:
shorter = 1
longer = 2
k = 3
输出: {3,4,5,6}
提示:
0 < shorter <= longer
0 <= k <= 100000
代码
class Solution {
public:
vector<int> divingBoard(int shorter, int longer, int k) {
if(k==0)
return vector<int>();
if(shorter==longer)
return vector<int>(1,shorter*k);
vector<int>res(k+1,0);
for(int i=0;i<=k;++i)
res[i]=shorter*(k-i)+longer*i;
return res;
}
};
思路
1.k==0,结束
2.短木板和长木板的长度相同,结果只有一种shorter*k
3.k个短木板,0个长木板,k-1个短木板,1个长木板…
35.LeetCode:剑指 Offer 28. 对称的二叉树-递归
时间:20200709
题目
剑指 Offer 28. 对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool Symmetric(TreeNode* p,TreeNode* q)
{
if(p&&q)
{
if(p->val!=q->val)
return false;
return Symmetric(p->left,q->right)&&Symmetric(p->right,q->left);
}
else if(!p&&!q)
return true;
else
return false;
}
bool isSymmetric(TreeNode* root) {
if(root==NULL)
return true;
return Symmetric(root,root);
}
};
思路
练习递归
36.LeetCode:174.地下城游戏-DP
时间:20200712
题目
174.地下城游戏
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2 (K) -3 3
-5 -10 1
10 30 -5 §
说明:
骑士的健康点数没有上限。
任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
代码
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int m=dungeon.size();
int n=dungeon[0].size();
if(m==0||n==0)
return 0;
vector<vector<int>> dp(m,vector<int>(n,0));
for(int i=m-1;i>=0;--i)
{
for(int j=n-1;j>=0;--j)
{
if(i==m-1&&j==n-1)
dp[i][j]=max(1,1-dungeon[i][j]);
else if(i==m-1)
dp[i][j]=max(1,dp[i][j+1]-dungeon[i][j]);
else if(j==n-1)
dp[i][j]=max(1,dp[i+1][j]-dungeon[i][j]);
else
dp[i][j]=max(1,min(dp[i+1][j],dp[i][j+1])-dungeon[i][j]);
}
}
return dp[0][0];
}
};
思路
反向动态规划。
37.LeetCode:20. 三角形最小路径和-DP
时间:20200714
题目
120.三角形最小路径和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
代码
思路1:自顶向下,递推公式 minPath[i][j] = Min()minPath[i-1][j-1], minPath[i-1][j]) + a[i][j],
但显然要考虑特殊边界位置,即最左侧,最右侧位置是不同的。
自顶向下
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
/* 自顶向下,考虑边界条件要特殊处理 , minPath[i][j] = Min()minPath[i-1][j-1], minPath[i-1][j]) + a[i][j],
最左、右列要特殊处理
最左: minPath[i][j] = minPath[i-1][j] + a[i][j]
最右: minPath[i][j] = minPath[i-1][j-1] + a[i][j]
*/
int rowSize = triangle.size();
vector<vector<int>> minPath(triangle);
if (triangle.size() == 1) {
return triangle[0][0];
}
minPath[0][0] = triangle[0][0];
minPath[1][0] = minPath[0][0] + triangle[1][0];
minPath[1][1] = minPath[0][0] + triangle[1][1];
for(int i=2;i<triangle.size();i++) {
for(int j=0;j<triangle[i].size();j++) {
// 最左侧
if(j==0) minPath[i][j] = minPath[i-1][j] + triangle[i][j];
// 最右侧
else if(j==triangle[i].size()-1) minPath[i][j] = minPath[i-1][j-1] + triangle[i][j];
else minPath[i][j] = min(minPath[i-1][j-1], minPath[i-1][j]) + triangle[i][j];
}
}
// c++11新方法 max/ min_element 的使用请注意,不需要sort再打印了哦
return *std::min_element(minPath[rowSize-1].begin(), minPath[rowSize-1].end() ) ;
}
};
思路2: 自底向上 ,这种思路的好处是上面越来越小,没有边界的特殊处理
// 动态规划, 自底向上 递推式 dp[i][j] = min(dp[i+1][j], dp[i+1[j+1]) + triangle[i][j];
int rowSize = triangle.size();
vector<vector<int>> dp(triangle);
for(int i=rowSize-2;i>=0;i--) {
for(int j=0; j<triangle[i].size(); j++) {
dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j];
}
}
return dp[0][0];
}
38.LeetCode:64.最小路径和-DP
时间:20200722
题目
64.最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
代码
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size()-1;
int n=grid[0].size()-1;
vector<vector<int>>dp(m+1,vector<int>(n+1));
dp[0][0]=grid[0][0];
for(int i=1;i<=m;++i)
{
dp[i][0]=dp[i-1][0]+grid[i][0];
}
for(int j=1;j<=n;++j)
{
dp[0][j]=dp[0][j-1]+grid[0][j];
}
for(int i=1;i<=m;++i)
{
for(int j=1;j<=n;++j)
{
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[m][n];
}
};
思路
自己做出来的动态规划,不容易啊。
39.LeetCode:1025.除数博弈
时间:20200724
1025.除数博弈
爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。
最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:
选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。
只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。
示例 1:
输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
示例 2:
输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。
提示:
1 <= N <= 1000
代码
class Solution {
public:
int choose(int N)
{
for(int i=1;i<N;i++)
{
if(N%i==0)
return i;
}
return 0;
}
bool divisorGame(int N) {
int state=0;
while(N>1)
{
state++;
int x=choose(N);
if(x==0)
break;
N=N-x;
}
if(state%2==1)
return true;
else
return false;
}
};
看到题解吐了
class Solution {
public:
bool divisorGame(int N) {
return N % 2 == 0;
}
};
40.LeetCode:100.相同的树-DFS或BFS
时间:20200726
100.相同的树
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
代码
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==NULL&&q==NULL)
return true;
if(p==NULL&&q!=NULL)
return false;
if(q==NULL&&p!=NULL)
return false;
if(p->val!=q->val)
return false;
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
};
思路
递归
41.LeetCode:337. 打家劫舍 III-递归+dp
时间:20200805
337.打家劫舍 III
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
unordered_map <TreeNode*, int> f, g;
void dfs(TreeNode* o) {
if (!o) {
return;
}
dfs(o->left);
dfs(o->right);
f[o] = o->val + g[o->left] + g[o->right];
g[o] = max(f[o->left], g[o->left]) + max(f[o->right], g[o->right]);
}
int rob(TreeNode* o) {
dfs(o);
return max(f[o], g[o]);
}
};
思路
用先序遍历再DP失败。
考虑为偷这个节点,和不偷这个节点,要好理解点。(递归真的难,DP也难。难上加难)
42.LeetCode:696. 计数二进制子串
时间:20200805
696.计数二进制子串
给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。
重复出现的子串要计算它们出现的次数。
示例 1 :
输入: “00110011”
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
请注意,一些重复出现的子串要计算它们出现的次数。
另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。
示例 2 :
输入: “10101”
输出: 4
解释: 有4个子串:“10”,“01”,“10”,“01”,它们具有相同数量的连续1和0。
注意:
s.length 在1到50,000之间。
s 只包含“0”或“1”字符。
代码
class Solution {
public:
int countBinarySubstrings(string s) {
vector<int>arr;
int count=1;
for(int i=0;i<s.size();++i)
{
if((i+1)<s.size()&&s[i]==s[i+1])
count++;
else
{
arr.push_back(count);
count=1;
}
}
int res=0;
for(int j=0;j<arr.size()-1;++j)
{
res+=min(arr[j],arr[j+1]);
}
return res;
}
};
思路
按字符分组
我们可以将字符串 s 按照 00 和 11 的连续段分组,存在counts 数组中,例如 s = 00111011,可以得到这样的 counts 数组:counts={2,3,1,2}。这里counts数组中两个相邻的数一定代表的是两种不同的字符。假设counts数组中两个相邻的数字为 u 或者 v,它们对应着 u个 0 和 v个 1,或者 u个 1 和 v 个 0。它们能组成的满足条件的子串数目为min{u,v},即一对相邻的数字对答案的贡献。
43.LeetCode:剑指 Offer 57 - II. 和为s的连续正数序列-滑动窗口
时间:20200805
剑指 Offer 57 - II. 和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
代码
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
int i=1;
int j=1;
vector<vector<int>>res;
int sum=0;
while(i<=target/2)
{
if(sum<target)
{
sum+=j;
++j;
}
else if(sum>target)
{
sum-=i;
++i;
}
else if(sum==target)
{
vector<int>window;
for(int k=i;k<j;k++)
{
window.push_back(k);
}
res.push_back(window);
sum-=i;
++i;
}
}
return res;
}
};
思路
滑动窗口
44.LeetCode:733.图像渲染-DFS或BFS
时间:20200816
733.图像渲染
有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像。
示例 1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。
注意:
image 和 image[0] 的长度在范围 [1, 50] 内。
给出的初始点将满足 0 <= sr < image.length 和 0 <= sc < image[0].length。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535]内。
代码
class Solution {
public:
void DFS(vector<vector<int>>& image,int sr,int sc,int m,int n,int newColor,int start,vector<vector<int>>&view)
{
if(sr<0 || sc<0 || sr>=m || sc>=n)
return ;
//up
if(sr-1>=0&&start==image[sr-1][sc]&&1!=view[sr-1][sc])
{
view[sr-1][sc]=1;
image[sr-1][sc]=newColor;
DFS(image,sr-1,sc,m,n,newColor,start,view);
}
//down
if(sr+1<m&&start==image[sr+1][sc]&&1!=view[sr+1][sc])
{
view[sr+1][sc]=1;
image[sr+1][sc]=newColor;
DFS(image,sr+1,sc,m,n,newColor,start,view);
}
//left
if(sc-1>=0&&start==image[sr][sc-1]&&1!=view[sr][sc-1])
{
view[sr][sc-1]=1;
image[sr][sc-1]=newColor;
DFS(image,sr,sc-1,m,n,newColor,start,view);
}
//right
if(sc+1<n&&start==image[sr][sc+1]&&1!=view[sr][sc+1])
{
view[sr][sc+1]=1;
image[sr][sc+1]=newColor;
DFS(image,sr,sc+1,m,n,newColor,start,view);
}
else
return;
}
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
int m=image.size(),n=image[0].size();
int start=image[sr][sc];
vector<vector<int>> view(m,vector<int>(n,0));
view[sr][sc]=1;
DFS(image,sr,sc,m,n,newColor,start,view);
image[sr][sc]=newColor;
return image;
}
};
思路
DFS,注意边界条件,终于能写出来一些了(虽然写的low)
45.LeetCode:109. 有序链表转换二叉搜索树-快慢指针和递归
时间:20200818
109.有序链表转换二叉搜索树
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
/**
* 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:
TreeNode* build_BT(vector<int>&arr,int left,int right)
{
if(left>right)
return NULL;
int mid=(right-left)/2+left;
TreeNode *root=new TreeNode(arr[mid]);
root->left=build_BT(arr,left,mid-1);
root->right=build_BT(arr,mid+1,right);
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
vector<int>arr;
if(head==NULL)
return NULL;
while(head)
{
arr.push_back(head->val);
head=head->next;
}
int left=0;
int right=arr.size()-1;
return build_BT(arr,left,right);
}
};
思路
将链表的结果存放在vector中,每次取中间的数,构建BST。
题解的快慢指针+递归更好
46.LeetCode:647.回文子串-中心拓展
时间:20200819
647.回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:“abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”
示例 2:
输入:“aaa”
输出:6
解释:6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”
提示:
输入的字符串长度不会超过 1000 。
代码
class Solution {
public:
int countSubstrings(string s) {
int length=s.size();
int result=0;
for(int i=0;i<length;i++)
{
//奇数的回文数
int l=i,r=i;
while(l>=0&&r<length)
{
if(s.at(l--)==s.at(r++))
result++;
else
break;
}
//偶数的回文数 这个数必须等于它的下一个数,两边一起扩展
if(i+1<length&&s[i]==s[i+1])
{
int l=i,r=i+1;
while(l>=0&&r<length)
{
if(s.at(l--)==s.at(r++))
result++;
else
break;
}
}
}
return result;
}
};
思路
自己用暴力法过了,搞不懂马拉车,看的题解是这个(侵删)
47.LeetCode:剑指 Offer 39. 数组中出现次数超过一半的数字-投票
时间:20200821
剑指 Offer 39. 数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:
1 <= 数组长度 <= 50000
代码
class Solution {
public:
int majorityElement(vector<int>& nums) {
int result=0;
int count=0;
for(int i=0;i<nums.size();i++)
{
if(count==0)
{
result=nums[i];
count++;
}
else
{
if(nums[i]==result)
count++;
else
count--;
}
}
return result;
}
};
思路
摩尔投票
48.LeetCode:剑指 Offer 66.构建乘积数组
时间:20200824
剑指 Offer 66.构建乘积数组
给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
示例:
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
提示:
所有元素乘积之和不会溢出 32 位整数
a.length <= 100000
代码
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
int n=a.size();
vector<int>L(n,1);
vector<int>R(n,1);
for(int i=1;i<n;++i)
{
L[i]=L[i-1]*a[i-1];
}
for(int j=n-2;j>=0;--j)
{
R[j]=R[j+1]*a[j+1];
}
for(int k=0;k<n;++k)
{
a[k]=L[k]*R[k];
}
return a;
}
};
思路
暴力是超时的
49.LeetCode:486. 预测赢家
时间:20200901
486.预测赢家
给定一个表示分数的非负整数数组。 玩家 1 从数组任意一端拿取一个分数,随后玩家 2 继续从剩余数组任意一端拿取分数,然后玩家 1 拿,…… 。每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。
给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最大化。
示例 1:
输入:[1, 5, 2]
输出:False
解释:一开始,玩家1可以从1和2中进行选择。
如果他选择 2(或者 1 ),那么玩家 2 可以从 1(或者 2 )和 5 中进行选择。如果玩家 2 选择了 5 ,那么玩家 1 则只剩下 1(或者 2 )可选。
所以,玩家 1 的最终分数为 1 + 2 = 3,而玩家 2 为 5 。
因此,玩家 1 永远不会成为赢家,返回 False 。
示例 2:
输入:[1, 5, 233, 7]
输出:True
解释:玩家 1 一开始选择 1 。然后玩家 2 必须从 5 和 7 中进行选择。无论玩家 2 选择了哪个,玩家 1 都可以选择 233 。
最终,玩家 1(234 分)比玩家 2(12 分)获得更多的分数,所以返回 True,表示玩家 1 可以成为赢家。
提示:
1 <= 给定的数组长度 <= 20.
数组里所有分数都为非负数且不会大于 10000000 。
如果最终两个玩家的分数相等,那么玩家 1 仍为赢家。
做题
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
// 模拟真实情况下,A,B轮流选牌的过程,求出结果
return helper(0, nums.size() - 1, 0, 0, true, nums);
}
//分别为 左边可取的位置,右边可取的位置,A的得分,B的得分, 轮到谁选牌, nums数组
bool helper(int left, int right, int score_A, int score_B, bool turn_to_A, vector<int>& nums) {
if (left > right) //左右越界,没有牌了,比较得分,判断胜负(以A为主角)
return score_A >= score_B;
if (turn_to_A) //轮到A选牌,A是主角,只要左边或者右边有一种必胜情况,就说明可以必胜
return helper(left + 1, right, score_A + nums[left], score_B, false, nums) || helper(left, right - 1, score_A + nums[right], score_B, false, nums);
else //轮到B选牌,不管B怎么选,此时只有左右两边都保证A是必胜的,才能保证A最终必胜!
return helper(left + 1, right, score_A, score_B + nums[left], true, nums) && helper(left, right - 1, score_A, score_B + nums[right], true, nums);
}
};
思路
DFS或者DP
50.LeetCode:347. 前 K 个高频元素-map+pair
时间:20200907
347.前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
你可以按任意顺序返回答案。
代码
class Solution {
public:
static bool cmp(pair<int,int>a, pair<int,int>b){
return a.second>b.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int,int>arr;
for(auto i:nums)
{
arr[i]++;
}
vector<int>res;
vector<pair<int,int>>pp;
for(map<int,int>::iterator it=arr.begin();it!=arr.end();it++)
{
pp.push_back(pair<int,int>(it->first,it->second));
}
sort(pp.begin(),pp.end(),cmp);
for(vector<pair<int,int>>::iterator it=pp.begin();it!=pp.end();it++)
{
if(k==0)
break;
res.push_back(it->first);
k--;
}
return res;
}
};
思路
将key和value放进map中,将map按照value从大到小排列
将前K个放进结果