2019.1.15 leetcode 刷题总结
题号:122
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
我的想法:
- 刚开始看题目的时候被题目迷惑了,题目说不能进行多次交易,我就想最大利润应该是在两种情况下的最大值:第一种情况,整个序列最大值减去最小值,且最大值在最小值之后;第二种情况,当后一位大于前一位时,记录差值并累加。
- 后来我发现,在一个非递减序列中(类似于[1,2,3,4]或者[1,2,2,3]这样的序列),其中两个数最大的差值一定是尾减头,这是大家都清楚的,这个差值还等于序列中任意的一个值减去序列的首数字加上序列的尾数字减去这个值,即非递减序列[a,b]中存在一个x,有 b-a = (x-a)+(b-x)。
- 若在整个所给的序列中,在最大值和最小值之间不是非递增序列,那么,其中几个递增序列的和一定大于整个序列中最大值见最小值。
- 因此,针对该题,虽然说不可以多次交易,但由第二条我们知道,如果是非递减序列,得到的结果是相同的。
- 所以,遍历数组,首先比较后面一位的数字是否大于前面的数字,若大于记录差值,若不大于,指针后移
对应程序:
// java
class Solution {
public int maxProfit(int[] prices) {
// 参数检查
if(prices == null || prices.length == 0){
return 0;
}
// 当前买入的价格
int buyPrice = prices[0];
// 买入价格的后一个位置索引
int nextPrice = 1;
// 利润
int res = 0;
while(nextPrice < prices.length) {
// 当买入之后的价格大于当前买入的价格时
if(prices[nextPrice] >= buyPrice) {
// 类升序序列(1,2,3或1,2,2,3)最大值就是尾减头
// 也等于序列中的值两两相减
res += prices[nextPrice] - buyPrice;
}
buyPrice = prices[nextPrice];
nextPrice++;
}
return res;
}
}
题号:453
给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。每次移动可以使 n - 1 个元素增加 1
示例:
输入:
[1,2,3]
输出:
3
解释:
只需要3次移动(注意每次移动会增加两个元素的值):
[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]
我的想法:
- 长度为n的数组,当经过a次“移动”后,数组中的所有数字相等。
- a次移动带来的影响是:数组所有数字的和多了a*(n-1);
- 可以得到经过a次移动后,数组中所有的数字的值为:(a*(n-1) + 原数组的和sum)/ n
- 原数组中最小值min一定参与每次的“移动”,因此得到(方程)等式:(a*(n-1) + 原数组的和sum)/ n = a + min,整理后得到:a = sum - n*(min)
对应程序:
// java
class Solution {
public int minMoves(int[] nums) {
int length = nums.length;
int sum = 0;
int min = Integer.MAX_VALUE;
for(int num : nums) {
sum += num;
if(num < min) {
min = num;
}
}
return sum - length * min;
}
}
题号:908
给定一个整数数组 A,对于每个整数 A[i],我们可以选择任意 x 满足 -K <= x <= K,并将 x 加到 A[i] 中。
在此过程之后,我们得到一些数组 B。
返回 B 的最大值和 B 的最小值之间可能存在的最小差值
示例 1:
输入:A = [1], K = 0
输出:0
解释:B = [1]
示例 2:
输入:A = [0,10], K = 2
输出:6
解释:B = [2,8]
示例 3:
输入:A = [1,3,6], K = 3
输出:0
解释:B = [3,3,3] 或 B = [4,4,4]
我的想法:
- x是任取[-K,K]的,对于所给数组中的每一个数,所加的x可以不同
- 新的数组B的最大值和最小值的最小差值只和B中的最大值和最小值相关,换句话来说,也就是和原数组A的最大值和最小值相关
- 想要获得最小差值,一定是让最大值尽可能的小,最小值尽可能地大,因此,原数组的最大值要减去K,最小值应该加上K
- 若原数组A中最大值和最小值的差值小于2K,那么他们最终会变成最大值和最小值相等的数组,如示例3
对应程序:
// java
class Solution {
public int smallestRangeI(int[] A, int K) {
int maxNum = getMaxNum(A);
int minNum = getMinNum(A);
int diff = maxNum - minNum;
if(2 * K >= diff) {
return 0;
}
return (maxNum - K) - (minNum + K);
}
private int getMinNum(int[] A) {
int res = Integer.MAX_VALUE;
for(int a : A) {
if(a < res) {
res = a;
}
}
return res;
}
private int getMaxNum(int[] A) {
int res = Integer.MIN_VALUE;
for(int a : A) {
if(a > res) {
res = a;
}
}
return res;
}
}
题号:747
在一个给定的数组nums中,总是存在一个最大元素 。
查找数组中的最大元素是否至少是数组中每个其他数字的两倍。
如果是,则返回最大元素的索引,否则返回-1。
示例 1:
输入: nums = [3, 6, 1, 0]
输出: 1
解释: 6是最大的整数, 对于数组中的其他整数,
6大于数组中其他元素的两倍。6的索引是1, 所以我们返回1.
示例 2:
输入: nums = [1, 2, 3, 4]
输出: -1
解释: 4没有超过3的两倍大, 所以我们返回 -1.
我的想法:
- 找到数组中的最大值和最大值的索引
- 找到数组中第二大的数
- 比较第二大的数字的2倍和最大值的大小
对应程序:
// java
class Solution {
public int dominantIndex(int[] nums) {
int max = Integer.MIN_VALUE;
int secondMax = Integer.MIN_VALUE;
int index = -1;
for(int i = 0; i < nums.length; ++i) {
if(nums[i] > max) {
// 在给最大值赋值时,应该将最大值赋给第二大的数
secondMax = max;
max = nums[i];
index = i;
}else if(nums[i] < max && nums[i] > secondMax) {
secondMax = nums[i];
}
}
if(secondMax * 2 > max) {
return -1;
}
return index;
}
}