leetcode笔记1
2022年第一周(1月5日-1月9日)
30天挑战的第一题 Move zeros
Give an array
nums, write a function to move all0's to the end of it while maintaining the relative order of the non-zero elements.
example
Input:[0,1,0,3,12]
output:[1,3,12,0,0]
我的结题思路
- 借用一个数组,记录下所有非零元素在原数组中的位置
- 重新填充数组,在数组的末尾全部补零
- 该算法需借助两个数组,4个变量,两次for循环,消耗内存较大。76ms 14.8MB
void moveZeroes(int* nums, int numsSize){
int i = 0;
int a = 0 ;
int j = 0;
int t;
int numsR[numsSize];
for (i = 0; i< numsSize; i++){ //记录所有非零变量的位置
if (nums[i] != 0){
numsR[j] = i;
j++;
a = j;
}
}
for (j = 0; j< numsSize; j++){ //重新填充数组
if(j< a){
t = numsR[j];
nums[j] = nums[t];
}else nums[j] = 0; //后面数组全部补零
}
}
算法1
知识点:
1.在不知道如何解决问题时先判断,什么情况是条件还没有满足
2.在遇到没有完成的情况时,需要采取的措施 局部修正,重复执行直到没有错误
3.如何判断for循环里有一次循环是和其他不一样的?
4.该算法和第一种算法相比,时间更长因为每次遇到错误,修正之后就会退出;但是占用空间更短。超出时间限制
void moveZeroes(int* nums, int numsSize){
// 1)我怎么知道还没有完成?
// 通常检查是比较简单的
// 2)当发现局部的错误时就交换
int count = 0;
while(true){ //这个while最多会跑numsSize次
count = 0;
for(int i= 0; i < (numsSize - 1); i++){
if (nums[i] == 0 && nums[i+1] != 0){ //还没有完成,左为零右不是零
//当发现没有完成时就交换
int t = nums[i];
nums[i] = nums[i+1];
nums[i+1] = t;
count++;
break; //去除此break依然可以运行,并且时间会大幅减少为508ms
}
}
if (count == 0){
break; //如果没有不一样的情况,即所有的if都不成立,已经完成条件了
}
}
}
算法2(two pointers)
知识点:
1.可以每次完成一部分(子问题),即每发现一个零就移动到最右边 重复执行
2.改进算法: 可以直接写答案,采用双下标的方法,利用两个index指向同一个数组,因为
j永远会比i慢3.该算法时间和空间都比较小
4.直接修改原始阵列,称为 in-place
void moveZeroes(int* nums, int numsSize){
//先放不是零的
//再放是零的
for(int i = 0; i < numsSize; i++){
if(nums[i] != 0){
nums[j] = nums[i];
j++;
}
}
//再放零的数(补零)
for(; j < numsSize; j++){
nums[j]=0;
}
}
如果无法保证在计算过程中j永远会比i慢,即j<=i,可以先将数组暂存
void moveZeroes(int* nums, int numsSize){
//先放不是零的
//再放是零的
int ans[numsSize];
int j= 0;
for(int i = 0; i < numsSize; i++){
if(nums[i] != 0){
ans[j] = nums[i];
j++;
}
}
//再放零的数(补零)
for(; j < numsSize; j++){
nums[j]=0;
}
for(int i = 0;i< numsSize; i++){
nums[i] = ans[i]; //C语言数组的赋值只能用for循环
}
}
题目不需要追求最完美的解法,需要掌握的是通用类的算法。因为实际中的问题往往是不完美的,亦不存在完美的解。故最推荐最后一种算法!
30天挑战的第二题 Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. you may complete as many transactions as you like(i.e., buy one and sell one share of the stock times).
Note: You may not engage in multiple transactions at the same time(i.e., you may sell the stock before you buy again)
example
Input:[7,1,5,3,6,4]
output:7
Explanation: Buy on day 2(price =1) and sell on day 3(price = 5), profit = 5-1 =4.
Then buy on day 4 (price = 3 ) and sell on day 5 (price = 6), profit = 3.
sum of the profit is 4 + 3 = 7.
算法1
难点
若将所有的买卖方式找到,并找出最大利润是不现实的,因为所有买卖方式的组合太多,呈指数次分布。
分析:
可以反向思考,即从右往左,什么时候卖彩票
最后一天要不要卖?
如果最后一天不卖,最后一天也不能买了。
那么数组
prices:[7,1,5,3,6,4]可以简化为[7,1,5,3,6]。阵列就变小了如果最后一天要卖,决策问题就变成在哪一天买。
组合可以是
(6,4)(3,4)(5,4)(1,4)(7,4)此时可以将问题拆解为:
[7,1,5,3,6]+(6,4)=>maxProfit(prices,5)+(4-6)
[7,1,5,3]+(3,4)=>maxProfit(prices,4)+(4-3)
[7,1,5]+(5,4)=>maxProfit(prices,3)+(4-5)
[7,1]+(1,4)=>maxProfit(prices,2)+(4-1)
[7]+(7,4)=>maxProfit(prices,1)+(4-7)涉及到递归,递归需要设置明确的边界条件,即最后一次递归的值
此方法会超时,因为递归的次数太过。
int maxProfit(int* prices, int pricesSize){
int profit;
int max = 0;
if(pricesSize <= 1) return 0; //递归的边界条件
//假设不卖
profit = maxProfit(prices,pricesSize-1);
if (profit >max){
max = profit;
}
//假设卖
for( int i = 1;i < pricesSize-1; i++){
profit = maxProfit(prices,i) + prices[pricesSize - 1]-prices[i - 1];
if (profit >max){
max = profit;
}
}
return max;
}
算法2
分析:
该算法是在上一算法的基础上进行的改进
用一个矩阵存储利润的答案
使用动态规划,从最小的开始,将利润存储在数组中,则后面的仅需对数组索引而已
但是此函数的时间还是比较长,需要两层for循环
int maxProfit(int* prices, int pricesSize){
if(pricesSize <= 1) return 0; //递归的边界条件
int profits[pricesSize+1];
profits[1] = 0;
for (int k = 2; k <= pricesSize; k++){
int profit;
int max = 0;
//假设不卖
profit = profits[k-1];
if (profit >max){
max = profit;
}
//假设卖
for( int i = 1;i < k-1; i++){
profit = profits[i] + prices[k - 1]-prices[i - 1];
if (profit >max){
max = profit;
}
}
profits[k] = max;
}
return profits[pricesSize];
}
算法3
分析:
只对相邻的两天进行买卖,即
(1,5)和(3,6)即只判断相邻的两天买卖是否可以盈利
如何判断这种算法可以实现所需的功能?
证明! 贪心法(Greedy)
该算法是对的,但是数学上证明该思路是对的,比较困难。 演算法设计与分析
int maxProfit(int* prices, int pricesSize){
int total = 0;
for (int i = 0; i < pricesSize -1; i++){
if(prices[i] < prices[i+1]){
total = total + prices[i+1]-prices[i];
}
}
return total;
}

浙公网安备 33010602011771号