https://leetcode.com/problems/house-robber-ii/description/
你是一个专业的强盗,计划抢劫沿街的房屋。每间房都藏有一定的现金,阻止你抢劫他们的唯一的制约因素就是相邻的房屋有保安系统连接,如果两间相邻的房屋在同一晚上被闯入,它会自动联系警方。
给定一个代表每个房屋的金额的非负整数列表,确定你可以在没有提醒警方的情况下抢劫的最高金额。
在上次盗窃完一条街道之后,窃贼又转到了一个新的地方,这样他就不会引起太多注意。这一次,这个地方的所有房屋都围成一圈。这意味着第一个房子是最后一个是紧挨着的。同时,这些房屋的安全系统与上次那条街道的安全系统保持一致。
给出一份代表每个房屋存放钱数的非负整数列表,确定你可以在不触动警报的情况下盗取的最高金额。
这是一道动态规划问题,将房子编号为1~n,设M[i]为盗贼到第i间房子时,盗取的最高金额,设V[i]表示第i间房子的金额。
盗贼一定会偷尽可能多的房屋,即当他偷到第n-4间房子时,他不会就此罢手,而一定会去偷第n-2、n-1间房子。
他也不会直接从第n-4间房子直接到第n间房子偷窃,因为这就少偷了第n-2间房子。
基于上述判断,我们可以断言,当盗贼偷窃第i间房子时,他一定是从第i-2或第i-3间房子过来的,即:
M[i] = max(M[i-2], M[i-3]) + V[i]
接下来考虑边界条件:
如果房子不是围成一圈(即第1间房子和第n间房子不相邻),那么盗贼盗取的最高金额必为max(M[n-1], M[n]),且为了最大收益,盗贼第一次盗取的房子一定是第1间或第2间。
如果房子围成一圈,我们仍可以用遍历的方式求解,当盗贼盗取了最高金额的前提下,还需要考虑以下情况:
1、若盗贼最后盗取的房子为第n间,那么他第一次盗取的房子一定不是第1间
2、若盗贼最后盗取的房子为第n间,那么他第一次盗取的房子可能是第3间
3、若盗贼第一次盗取的房子是第1间,那么他最后盗取的房子可能是第n-2间
用M[i][j]表示盗贼第一次盗取的房子为第i间时(1<=i<=3),盗取第j间房子能得到的最大收益,则盗贼盗取的最大金额必为:
M[2][n], M[3][n], M[1][n-1], M[2][n-1], M[1][n-2]中的最大值
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
int pre(vector arr[],int j,int i){
if(i-3<0)return arr[j][i-2];
return max(arr[j][i-2],arr[j][i-3]);
}
int rob(vector& nums) {
if(!nums.size())return 0;
vector arr[3]={vector(nums.size(),0),vector(nums.size(),0),vector(nums.size(),0)};
arr[0][0]=nums[0];
if(nums.size()>1)arr[1][1]=nums[1];
if(nums.size()>2)arr[2][2]=nums[2];
for(int i=2;i
https://leetcode.com/problems/triangle/description/
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
从上到下,从左到右遍历,每计算完一行后,都将结果保留在一个数组中。
根据这一行的结果,计算下一行的结果,如此循环,直到找到最后一行结果的最小值。
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
int minimumTotal(vector>& triangle) {
vector arr(triangle.size(),0),temp(triangle.size(),0);
int ans=1000000;
for(int i=0;i
https://leetcode.com/problems/jump-game/description/
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
遍历数组,设当前位置为i。
每一次都计算从位置i能跳到的最远位置,同时记录从位置1~i能跳到的最远位置。
如果最远位置大于或等于数组长度,说明可以跳到数组的最后一位。
如果到了当前位置i,但1~i-1能跳到的最远位置小于i,说明无法跳到位置i,即无法跳到数组的最后一位。
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
bool canJump(vector& nums) {
int maxn = 0;
for(int i = 0;i=nums.size()-1)return true;
maxn = max(maxn, i+nums[i]);
}
return false;
}
};
https://leetcode.com/problems/gas-station/description/
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
说明:
如果题目有解,该答案即为唯一答案。
输入数组均为非空数组,且长度相同。
输入数组中的元素均为非负数。
遍历gas,当gas[i]>=cost[i]时,开始模拟汽车的行驶,即每一次i = (i + 1) % gas.size()
如果行驶过程中出现了汽车的油量小于当前位置的耗油量时,退出循环,继续遍历gas
如果汽车通过行驶能够回到原来的位置,说明可以从第i个加油站出发绕环路行驶一周
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
int canCompleteCircuit(vector& gas, vector& cost) {
for(int i=0;i=cost[j]){
gass-=cost[j];
j=(j+1)%gas.size();
gass+=gas[j];
flag++;
}
if(j==i){
return i;
}
}
return -1;
}
};
https://leetcode.com/problems/sort-list/description/
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
直接对链表进行快速排序即可。
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
void swap(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
ListNode* sortListPos(ListNode* begin, ListNode *mid, ListNode *end) {
if (begin == end || begin->next == end)return NULL;
int nval = begin->val;
ListNode *p = begin, *q = begin->next;
while (q != end) {
if (q->val < nval) {
p = p->next;
swap(p->val, q->val);
}
q = q->next;
}
swap(p->val, begin->val);
return p;
}
void qsortList(ListNode *begin,ListNode *end){
ListNode *mid=sortListPos(begin,end);
if(mid!=NULL){
qsortList(begin,mid);
qsortList(mid->next,end);
}
}
ListNode* sortList(ListNode* head) {
qsortList(head,NULL);
return head;
}
};
https://leetcode.com/problems/kth-largest-element-in-an-array/description/
在未排序的数组中找到第 k 个最大的元素。请注意,它是数组有序排列后的第 k 个最大元素,而不是第 k 个不同元素。
例如,
给出 [3,2,1,5,6,4] 和 k = 2,返回 5。
注意事项:
你可以假设 k 总是有效的,1 ≤ k ≤ 数组的长度。
本来是想用优先队列做的,后来发现题目数据太水,直接用标准库的sort排序后取倒数第k项,竟然比用优先队列更快。
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
int findKthLargest(vector& nums, int k) {
sort(nums.begin(),nums.end());
return nums[nums.size()-k];
}
};
https://leetcode.com/problems/merge-k-sorted-lists/description/
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
一开始是将合并2个排序链表的思路扩展到k个,即每一次循环都在k个链表里找到结点p,结点p有最小值。
然后让p指向下一个结点,再次循环,直到k个链表对应的结点都指向NULL为止。
后来改成用一次循环将所有链表与第一个链表合并,最后返回第一个链表。
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
ListNode* mergeList(ListNode *pre, ListNode *after){
ListNode *p=pre,*q=after;
if(p==NULL)return q;
if(q==NULL)return p;
ListNode *res=new ListNode(0);
ListNode *r=res;
while(p!=NULL&&q!=NULL){
if(p->val>q->val){
r->next=q;
q=q->next;
}
else{
r->next=p;
p=p->next;
}
r=r->next;
}
if(p!=NULL)r->next=p;
if(q!=NULL)r->next=q;
return res->next;
}
ListNode* mergeKLists(vector& lists) {
if(lists.size()<1)return NULL;
if(lists.size()<2)return lists[0];
for(int i=1;i
https://leetcode.com/problems/median-of-two-sorted-arrays/description/
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
一开始是将两个数组直接合并,得到新的数组后,返回它的中位数。
由于leetcode的数据比较水,这样O(m+n)的方法也能过。
后来看了题解,发现可以用二分的方法将集合划分
假设A为第一个数组,B为第二个数组,只需要将A和B划分成两个集合。
A[1] A[2] ... A[i-1] | A[i] A[i+1] ... A[m]
B[1] B[2] ... B[j-1] | B[j] B[j+1] ... B[n]
两个集合满足A[i-1]
int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
if(nums1.size()>nums2.size())return findMedianSortedArrays(nums2,nums1);
int sizea=nums1.size(),sizeb=nums2.size();
if(sizea==0)return sizeb%2?nums2[sizeb/2]:double(nums2[sizeb/2]+nums2[sizeb/2-1])/2;
int imin=0,imax=nums1.size(),midsize=(sizea+sizeb+1)/2,i=0,j=0,left=0,right=0;
while(imin<=imax){
i=(imin+imax)/2;
j=midsize-i;
if(i>0&&nums1[i-1]>nums2[j])imax=i;
else if(inums1[i])imin=i+1;
else{
left=(i==0)?nums2[j-1]:(j==0)?nums1[i-1]:max(nums1[i-1],nums2[j-1]);
right=(i==sizea)?nums2[j]:(j==sizeb)?nums1[i]:min(nums1[i],nums2[j]);
return (sizea+sizeb)%2?left:double(left+right)/2;
}
}
return -1;
}
};