leetcode初级算法网址
https://leetcode-cn.com/leetbook/detail/top-interview-questions-easy/
1、删除排序数组中的重复项
解题思路:
本题使用了双指针的技巧。个人理解,其实可以看成新生成了一个数组,只是为了节省空间,就使用了双指针进行原地修改。
值得注意的是,本题给了很多的限定:
- 数组是升序的
- 返回值是数组长度,这也在暗示原地修改
其次,注意下特殊情况:无需查重的(数组为空数组或者只有一个元素),直接返回numsSize即可。
双指针思想在本题中的实际应用:
我们可以考虑这个问题:输入一串数字进行存储,重复的除外。输入的这一串数字,也就是数组nums[]
,用变量i遍历读取,遍历完了的地址空间,因为不要求保留原始数据,所以都是可用的。如图,遍历到nums[2]的时候,nums[2]之前的地址位其实都是可用的,都已经读取过了,里边的值没必要管。
利用这一片地址空间(原地),来存储结果。此时,存储结果的就是指针j来标记。因此,指针j初始化为0,也没有从0开始遍历数组的必要,有重复发生的话,至少得是两个元素嘛,指针i就初始化为1。
接下来,用变量j指向的地址空间存储最终结果,每次遇到非重复元素,就需要记录下来,详见题解代码。
错误代码
//输入[1,1,2],输出[1]
int removeDuplicates(int* nums, int numsSize){
int i = 0,j = 0;
if(numsSize == 0)
return 0;
for(; i < numsSize-1; i++)
{
//nums[j] = nums[i];
if(nums[i] != nums[j])
{
j = j + 1;
nums[j] = nums[i];
}
}
return j + 1;
}
题解:
int removeDuplicates(int* nums, int numsSize)
{
if(numsSize < 2)
return numsSize;
int i = 1;
int j = 0;
for(; i < numsSize; i++)
{
if(nums[i] != nums[j])
{
nums[++j] = nums[i];
}
}
return j + 1;
}
特别注意:边界条件设置
2、买卖股票的最佳时机Ⅱ
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/submissions/
解题思路
类似贪心的思想,贪的就是只要有上涨的,就出售,每次出售利润的总和就是最终利润。这贪的局部最优解应该也是整体最优解,毕竟若是类似1,3,9的情况,每次上涨就出售,和涨的最多再出售结果都是能赚8,怎么说呢,9-1 = (3-1)+ (9-3)嘛,类似于化学里催化剂的作用嘛,断键需要的总能量那么多,加催化剂其实也一样。
错误代码:
/*
默认第一天的就是最小的
*/
int maxProfit(int* prices, int pricesSize){
//涨了就出售
if(pricesSize < 2)
return 0;
int i = 1;
int profit = 0;
int j = 0;
for(;i < pricesSize; i++)
{
if(prices[i] > prices[j])
{
profit = profit + prices[i] - prices[j];
j = i;
}
}
return profit;
}
题解
int maxProfit(int* prices, int pricesSize){
//涨了就出售
if(pricesSize < 2)
return 0;
int i = 1;
int profit = 0;
int j = 0;
for(;i < pricesSize; i++)
{
if(prices[i] > prices[j])
{
profit = profit + prices[i] - prices[j];
j = i;
}
else
j = i;
}
return profit;
}
/*j = i可以合并一下,好看~~*/
3、旋转数组
https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/x2skh7/
解题思路
方法1:使用一个数组暂存需要交换的值。
本题是指就是后k个数放到数组开始,其余的依次往后移。值得注意的是:当numsSize < k时,代表数组右移k-numsSize个数,类似于补码的思想。
//未考虑numsSize < k的正确处理方式
void rotate(int* nums, int numsSize, int k)
{
if(numsSize < 2 || numsSize <= k)
return;
int temp[numsSize - k];
int i = numsSize - k;
int j = 0;
for(;i < numsSize; i++)
{
temp[j] = nums[i];
j++;
}
for(i = numsSize - k -1; i >= 0; i--)
{
nums[i + k] = nums[i];
}
for(i = 0; i < k; i++)
{
nums[i] = temp[i];
}
return;
}
//修改后仍是numssize < k时,runtime不通过
void rotate(int* nums, int numsSize, int k)
{
if(numsSize < 2)
return;
if(numsSize <= k)
{
int i = 0;
int temp;
for(; i < numsSize / 2; i++)
{
temp = nums[i];
nums[i] = nums[numsSize - i - 1];
nums[numsSize - i - 1] = temp;
}
return;
}
else
{
int temp[numsSize - k];
int i = numsSize - k;
int j = 0;
for(;i < numsSize; i++)
{
temp[j] = nums[i];
j++;
}
for(i = numsSize - k -1; i >= 0; i--)
{
nums[i + k] = nums[i];
}
for(i = 0; i < k; i++)
{
nums[i] = temp[i];
}
return;
}
}
//用例为[1,2,3],2时,出现temp[1],长度为1的数组,而循环体中有temp[0]
void rotate(int* nums, int numsSize, int k)
{
if(numsSize == k)
return;
if(numsSize < k)
{
int i = 0;
int temp[numsSize];
for(; i < numsSize; i++)
{
temp[i] = nums[numsSize - i - 1];
}
for(i = 0; i < numsSize; i++)
{
nums[i] = temp[i];
}
return;
}
else
{
int temp[numsSize - k];
int i = numsSize - k;
int j = 0;
for(;i < numsSize; i++)
{
temp[j] = nums[i];
j++;
}
for(i = numsSize - k -1; i >= 0; i--)
{
nums[i + k] = nums[i];
}
for(i = 0; i < k; i++)
{
nums[i] = temp[i];
}
return;
}
}
题解
其实就相当于前(numsize-k)个和后k个换了个位置。
void rotate(int* nums, int numsSize, int k)
{
int temp[numsSize];
if(k > numsSize)
k = k % numsSize;
for (int i = 0; i < numsSize; i++)
{
if(i < k)
temp[i] = nums[numsSize -k + i];
else
temp[i] = nums[i - k];
}
for (int i = 0; i < numsSize; i++) {
nums[i] = temp[i];
}
}