目录
letter-combinations-of-a-phone-number(遍历,中等)
best-time-to-buy-and-sell-stock(遍历,简单)
best-time-to-buy-and-sell-stock-ii(遍历,简单)
remove-duplicates-from-sorted-array-ii(遍历,中等)
letter-combinations-of-a-phone-number(遍历,中等)
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
思路
先是常规的描述和判断边界条件
vector<string> letterCombinations(string digits) {
vector<string> a{"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector<string> c;
if(digits.empty())
{
c.push_back("");
return c;
}
接着,这里单独给c,push进去一个"",显的挺奇怪,这是因为在后面的循环过程中,要用到c中上一个的处理结果,这里是为初始状态下的c做准备。因为,后面会进行擦除(c.erase(c.begin(),c.begin()+len);),所以不必担心这个会带入到最后的结果里面。
c.push_back("");
后面就是开始遍历了,每次都将上次的结果取出来,然后,将上次结果的每个值,都与这次的字符相匹配组合,生成新的结果,存放到里面,最后,再把上次结果给抹掉。这样得到的结果,就是最后一次生成的结果了。
完整Code
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> a{"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector<string> c;
if(digits.empty())
{
c.push_back("");
return c;
}
c.push_back("");
for (int i=0;i<digits.size();i++)
{
int res=digits[i]-'2';//当前按键对应的字符串索引
int len=c.size(); //前一次处理好的字符串数
for(int i = 0;i<len;i++)//遍历前一次处理好的字符串
{
for (auto m:a[res])//遍历按键对应字符
{
c.push_back(c[i]+m);//将每一种组合放到末端
}
}
c.erase(c.begin(),c.begin()+len);//清除前一次的组合
}
return c;
}
};
best-time-to-buy-and-sell-stock(遍历,简单)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4] 输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1] 输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
思路
因为只运行完成一次,那么就记录整个序列里面最小的值,和在这个值后面的最大的值。
if(prices[i]<min_num)
min_num = prices[i];//更新最小值
并且,后面的记录下来每个当前节点和之前记录的最小值之间的利润(做差),利润最大的,就是返回。
那要是最小值出现在了后面,但后面没多少数了,怎么办,这种情况是不需要担心的,因为即便后面更新成了更小的数,没有大的价值再更后面对应,还是无法得到最大利润的。
else
max_profit = max(max_profit, prices[i]-min_num);
完整code
class Solution {
public:
int maxProfit(vector<int> &prices) {
int min_num = prices[0];
int max_profit = 0;
for(int i=1; i<prices.size(); ++i){
if(prices[i]<min_num)
min_num = prices[i];//更新最小值
else
max_profit = max(max_profit, prices[i]-min_num);
}
return max_profit;
}
};
best-time-to-buy-and-sell-stock-ii(遍历,简单)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4] 输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5] 输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1] 输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
思路
先明白,股票低的时候买进,高的时候卖,这样可以保证利润最大。
从头开始遍历,如果当前值比之后值大,那就直接跳过,因为这个时候是高价。如果后一个比前一个大,那么我把每次大出来的差值(利润)累加起来,那么最终得到的就是最终的利润最大的和了。
不用担心同一个节点是否可以买进和卖出。想想,如果这两个max是连续的,那可以买进后,只要利润增加,就都不卖;如果不连续,可以在差值的两个端点买进和卖出,再继续看下一个,总之,只要累加前-后的差值,最后得到的就是利润最大值了。
完整Code
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() == 0) return 0;
int max1 = 0;
for (int i = 0; i < prices.size()-1; i++)
{
if (prices[i] >= prices[i + 1])
continue;
else
{
max1 = max1 + prices[i+1] - prices[i];
}
}
return max1;
}
};
merge-sorted-array(遍历,简单)
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
思路
因为两个数组有序,所以,从两个数组的末尾开始比较,要把结果合并到第一个数组中去,如果两个值是第一个数组的大,就n1前移,继续跟当前n2做比较,反过来也一样。最后,把对应的值,插到对应的位置上。
这里说一句,为啥要从后往前遍历呢?这是因为,每次插进去一个值,就会让数组长度增加,那数组原本对应的下标也会变化,从前往后插,不会受数组下标的影响。
最后有个while(j>=0)的条件,是说,如果n1数列比较完了,但n2还没插完,就说明n2剩下来的每个数都比n1当前的数列中的每个数都大,所以,之间把剩下的都插到n1后面就行了。
完整code
class Solution {
public:
void merge(int nums1[], int m, int nums2[], int n) {
int i = m - 1, j = n - 1, index = m + n - 1;
while (i >= 0 && j >= 0)
nums1[index--] = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--];
while (j >= 0)
nums1[index--] = nums2[j--];
}
};
remove-duplicates-from-sorted-array-ii(遍历,中等)
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。
思路
思路非常的巧妙,适用于所有这种类型的问题,因为不能超过2,所以,设index=2;那么,开始将A中的元素逐个循环,这个IF指出,如果当前这个值等于开头值(初始时,index-2=0),那么不进行任何操作,继续循环,如果A[1]还是A[0],说明有两个相同的数字了,那么接着往下A[2]如果还等于A[0]怎么办?还是不会执行任何操作啊!不用担心,只要走到不等于A[0]的地方,A[index++]就会进行更新,会把A[3]给覆盖掉,因为index=2,保证了不会让第一个的值出现超过2次的。
这是因为A[i]和A[index-2]始终差两个字符的距离,index只会在当前点与之前出现不一样的时候,并且更新的时候都会将超过2的给覆盖掉。如果,出现次数低于两次,那index也会进行更新。(自己体会下,我叙述的不是太好。)
if (A[i] != A[index-2])
{
A[index++] = A[i];
}
完整code
class Solution {
public:
int removeDuplicates(int A[], int n) {
if (n < 2) return n;
int index = 2;
for (int i = 2; i < n;i++)
{
if (A[i] != A[index-2])
{
A[index++] = A[i];
}
}
return index;
}
};