打家劫舍系列题
难度简单1005收藏分享切换为英文关注反馈
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1] 输出:4 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
int rob(vector<int> &nums) {
int n = nums.size();
// 记录 dp[i+1] 和 dp[i+2]
int dp_i_1 = 0, dp_i_2 = 0;
// 记录 dp[i]
int dp_i = 0;
for (int i = 0; i <= n-1; i++) {
dp_i = max(dp_i_1, nums[i] + dp_i_2);
dp_i_2 = dp_i_1;
dp_i_1 = dp_i;
}
return dp_i;
}
int rob(vector<int>& nums) {
if(nums.size()==0) return 0;
if(nums.size()==1) return nums[0];
int n=nums.size();
vector<int> v(n);
v[0]=nums[0];
v[1]=max(nums[0],nums[1]);
for(int i=2;i<n;i++){
v[i]=max(v[i-2]+nums[i],v[i-1]);
}
return v[n-1];
}
难度中等345收藏分享切换为英文关注反馈
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [2,3,2] 输出: 3 解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
//分类解决环问题
class Solution {
public:
int get(vector<int>& nums,int start,int end){
int dp_i=0,dp_i_1=0,dp_i_2=0;
// int end=n-2,start=1;
for(int i=end;i>=start;i--){
dp_i=max(dp_i_1,dp_i_2+nums[i]);
dp_i_2=dp_i_1;
dp_i_1=dp_i;
}
return dp_i;
}
int rob(vector<int>& nums) {
if(nums.size()==0) return 0;
if(nums.size()==1) return nums[0];
int n=nums.size();
int ans=max(get(nums,0,n-2),get(nums,1,n-1));
return ans;
}
};
难度中等544
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
示例 1:
输入: [3,2,3,null,3,null,1] 3 / \ 2 3 \ \ 3 1 输出: 7 解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
示例 2:
输入: [3,4,5,1,3,null,1] 3 / \ 4 5 / \ \ 1 3 1 输出: 9 解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
class Solution {
public:
unordered_map<TreeNode*,int> mp;
int rob(TreeNode* root) {
if(root==NULL) return 0;
if(mp.count(root)) return mp[root];
//抢
int do1=root->val+
(root->left==NULL?0:rob(root->left->left)+rob(root->left->right))+
(root->right==NULL?0:rob(root->right->left)+rob(root->right->right));
//不抢
int do2=rob(root->left)+rob(root->right);
int res=max(do1,do2);
mp[root]=res;
return res;
}
};
难度中等372
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2 输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
进阶:
- 给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
- 要求算法的空间复杂度为O(n)。
- 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。
对于所有的数字,只有两类:
奇数:二进制表示中,奇数一定比前面那个偶数多一个 1,因为多的就是最低位的 1。
举例:
0 = 0 1 = 1
2 = 10 3 = 11
偶数:二进制表示中,偶数中 1 的个数一定和除以 2 之后的那个数一样多。因为最低位是 0,除以 2 就是右移一位,也就是把那个 0 抹掉而已,所以 1 的个数是不变的。
举例:
2 = 10 4 = 100 8 = 1000
3 = 11 6 = 110 12 = 1100
另外,0 的 1 个数为 0,于是就可以根据奇偶性开始遍历计算了。
作者:duadua
链接:https://leetcode-cn.com/problems/counting-bits/solution/hen-qing-xi-de-si-lu-by-duadua/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
vector<int> countBits(int num) {
vector<int> result(num+1);
result[0] = 0;
for(int i = 1; i <= num; i++)
{
if(i % 2 == 1)
{
result[i] = result[i-1] + 1;
}
else
{
result[i] = result[i/2];
}
}
return result;
}
难度中等421收藏分享切换为英文关注反馈
给定一个非空的整数数组,返回其中出现频率前 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:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> map;
for(int i : nums) map[i] ++; //遍历
priority_queue< pair<int,int>, vector< pair<int,int> >, greater< pair<int,int> > > q; //最小堆
for(auto it : map)
if(q.size() == k) { //队列满了
if(it.second > q.top().first) { //堆排
q.pop();
q.push(make_pair(it.second, it.first));
}
}
else q.push(make_pair(it.second, it.first));
vector<int> res;
while(q.size()) { //将优先队列中k个高频元素存入vector
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
难度中等440收藏分享切换为英文关注反馈
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string]
,表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a
或 2[4]
的输入。
示例 1:
输入:s = "3[a]2[bc]" 输出:"aaabcbc"
示例 2:
输入:s = "3[a2[c]]" 输出:"accaccacc"
示例 3:
输入:s = "2[abc]3[cd]ef" 输出:"abcabccdcdcdef"
示例 4:
输入:s = "abc3[cd]xyz" 输出:"abccdcdcdxyz"
难哭了不想看了
难度中等188
给出方程式 A / B = k
, 其中 A
和 B
均为用字符串表示的变量, k
是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0
。
示例 :
给定 a / b = 2.0, b / c = 3.0
问题: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
返回 [6.0, 0.5, -1.0, 1.0, -1.0 ]
输入为: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries
(方程式,方程式结果,问题方程式), 其中 equations.size() == values.size()
,即方程式的长度与方程式结果长度相等(程式与结果一一对应),并且结果值均为正数。以上为方程式的描述。 返回vector<double>
类型。
基于上述例子,输入如下:
equations(方程式) = [ ["a", "b"], ["b", "c"] ], values(方程式结果) = [2.0, 3.0], queries(问题方程式) = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ].
输入总是有效的。你可以假设除法运算中不会出现除数为0的情况,且不存在任何矛盾的结果。
无语
难度中等425
假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)
表示,其中h
是这个人的身高,k
是排在这个人前面且身高大于或等于h
的人数。 编写一个算法来重建这个队列。
注意:
总人数少于1100人。
示例
输入: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 输出: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
不会
难度中等350
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
- 每个数组中的元素不会超过 100
- 数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5] 输出: true 解释: 数组可以分割成 [1, 5, 5] 和 [11].
01背包问题,有空再看一下
//有点晕、再看看。。。。。啊
bool canPartition(vector<int>& nums) {
if(nums.size()==0||nums.size()==1) return false;
//01背包问题
int sum=0;
for(int num:nums) sum+=num;
if(sum%2!=0) return false;
sum/=2;
int n=nums.size();
vector<bool> dp(sum+1,false);
dp[0]=true;
for(int i=0;i<n;i++){
for(int j=sum;j>=0;j--)
if(j-nums[i]>=0)
dp[j]=dp[j]||dp[j-nums[i]];
}
return dp[sum];
}
系列:
难度简单395收藏分享切换为英文关注反馈
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5 / \ 4 8 / / \ 11 13 4 / \ \ 7 2 1
返回 true
, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2
。
class Solution {
public:
bool hasPathSum(TreeNode *root, int sum) {
if (root == nullptr) {
return false;
}
if (root->left == nullptr && root->right == nullptr) {
return sum == root->val;
}
return hasPathSum(root->left, sum - root->val) ||
hasPathSum(root->right, sum - root->val);
}
};
//也可以用bfs哦
难度中等287收藏分享切换为英文关注反馈
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1
返回:
[ [5,4,11,2], [5,8,4,5] ]
class Solution {
private:
vector<vector<int>> ans;
vector<int> path;
public:
void findPath(TreeNode* root,int sum){
if(!root) return;
path.push_back(root->val);
if(!root->left && !root->right && root->val==sum) ans.push_back(path);
findPath(root->left,sum-root->val);
findPath(root->right,sum-root->val);
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int sum) {
findPath(root,sum);
return ans;
}
};
难度中等523收藏分享切换为英文关注反馈
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
示例:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 10 / \ 5 -3 / \ \ 3 2 11 / \ \ 3 -2 1 返回 3。和等于 8 的路径有: 1. 5 -> 3 2. 5 -> 2 -> 1 3. -3 -> 11
本题是在112题路径之和的基础上进行节点再次递归。112题题解链接
区别于112题的是本体不要求根节点出发,也不要求叶节点截止。
所以为了能够实现在树中间的节点之间求和,将每个节点都作为根节点进行遍历求和,然后修改判断条件为只要和等于sum即视为一次有效求和。
作者:niu-niu-niu-c
链接:https://leetcode-cn.com/problems/path-sum-iii/solution/shuang-di-gui-zhi-jie-zai-112ti-ji-chu-shang-jin-x/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
private:
int x = 0;
int i = 0;
public:
int pathSum(TreeNode* root, int sum) {
if(root == NULL)
return 0;
pathSum(root->left, sum);
pathSum(root->right, sum);
deep(root, sum, x);
return i;
}
void deep(TreeNode* root, int sum,int z){
if(root == NULL)
return ;
z += root->val;
if( z == sum)
i++;
deep(root->left, sum, z);
deep(root->right, sum,z);
}
};
难度中等337收藏分享切换为英文关注反馈
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
- 字母异位词指字母相同,但排列不同的字符串。
- 不考虑答案输出的顺序。
示例 1:
输入: s: "cbaebabacd" p: "abc" 输出: [0, 6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。
示例 2:
输入: s: "abab" p: "ab" 输出: [0, 1, 2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
//那岂不是限制了滑动窗口的大小为3?
unordered_map<char,int> need,window;
for(char c:p) need[c]++;
int left=0;int right=0;
vector<int> ans;
int valid=0;
while(right<s.size()){
char c=s[right];
right++;
//更新
if(need.count(c)){
window[c]++;
if(window[c]==need[c]) valid++;
}
while(right-left>=p.size()){
if(valid==need.size()) ans.push_back(left);
char c=s[left];
left++;
if(need.count(c)){
if(window[c]==need[c]) valid--;
window[c]--;
}
}
}
return ans;
}
};
难度简单421收藏分享切换为英文关注反馈
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
输入: [4,3,2,7,8,2,3,1] 输出: [5,6]
算法:
遍历输入数组的每个元素一次。
我们将把 |nums[i]|-1 索引位置的元素标记为负数。即 nums[∣nums[i]∣−1]×−1nums[|nums[i] |- 1] \times -1nums[∣nums[i]∣−1]×−1 。
然后遍历数组,若当前数组元素 nums[i] 为负数,说明我们在数组中存在数字 i+1。
可以通过以下图片示例来帮助理解。
作者:LeetCode
链接:https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/solution/zhao-dao-suo-you-shu-zu-zhong-xiao-shi-de-shu-zi-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
// Iterate over each of the elements in the original array
for (int i = 0; i < nums.length; i++) {
int newIndex = Math.abs(nums[i]) - 1;
if (nums[newIndex] > 0) {
nums[newIndex] *= -1;
}
}
List<Integer> result = new LinkedList<Integer>();
for (int i = 1; i <= nums.length; i++) {
if (nums[i - 1] > 0) {
result.add(i);
}
}
return result;
}
}
难度中等420收藏分享切换为英文关注反馈
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
说明:
- 所有输入均为小写字母。
- 不考虑答案输出的顺序。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> res;
unordered_map <string,vector<string> > m;
for(string& s : strs)
{
string t = s;
sort(t.begin(),t.end());
m[t].push_back(s); //t为单词的按顺序排列,作为key值,m[t]则为该单词的异位词构成的vector,作为value值
}
for(auto& n : m) //n为键和值组成的pair
res.push_back(n.second);
return res;
}
};