给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
输入: [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,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
};
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function (prices) {
let r = 0;
prices.reduce((p, v) => {
r += Math.max(0, v - p);//把后一项和前一项的差值为正数的相加,就是赚的最多的
return v;
});
return r;
};
//简写版
var maxProfit = function(prices, r = 0) {
let r=0;
return prices.reduce((p,v)=>(r+=Math.max(0,v-p),v)),r
};
我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。
(这里,平面上两点之间的距离是欧几里德距离。)
你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。
输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释:
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。
输入:points = [[3,3],[5,-1],[-2,4]], K = 2
输出:[[3,3],[-2,4]]
(答案 [[-2,4],[3,3]] 也会被接受。)
1 <= K <= points.length <= 10000
-10000 < points[i][0] < 10000
-10000 < points[i][1] < 10000
/**
* @param {number[][]} points
* @param {number} K
* @return {number[][]}
*/
var kClosest = function (points, K) {
};
/**
* @param {number[][]} points
* @param {number} K
* @return {number[][]}
*/
var kClosest = function (points, K) {
let arr = [];
for (var i = 0; i < points.length; i++) {
let temp = points[i];
arr.push({
id: Math.sqrt(
Math.pow(Math.abs(temp[0]), 2) + Math.pow(Math.abs(temp[1]), 2)
),
item: temp,
});
}
return arr
.sort((a, b) => {
return a.id - b.id;
})
.map((item) => item.item)
.slice(0, K);
};
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var nextPermutation = function (nums) {
let i = nums.length - 1 - 1;
// 从右向左找到第一个降序位置
while ((nums[i] >= nums[i + 1]) && i >= 0) {
i--;
}
if (i >= 0) {
//有降序节点
let j = nums.length - 1;
//从右往左找到一个刚好比降序节点大的值进行交换
while (nums[j] <= nums[i]) {
j--;
}
[nums[i], nums[j]] = [nums[j], nums[i]]
}
// 把降序节点右边的值(递减列)进行从小到大排序
let l = i + 1, r = nums.length - 1;
while (r > l) {
if (nums[l] > nums[r]) {
let value = nums[r];
nums[r] = nums[l];
nums[l] = value;
}
l++;
r--;
}
};
电子游戏“辐射4”中,任务 “通向自由” 要求玩家到达名为 “Freedom Trail Ring” 的金属表盘,并使用表盘拼写特定关键词才能开门。
给定一个字符串 ring ,表示刻在外环上的编码;给定另一个字符串 key ,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。
最初,ring 的第一个字符与 12:00 方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符。
旋转 ring 拼出 key 字符 key[i] 的阶段中:
您可以将 ring 顺时针或逆时针旋转 一个位置 ,计为1步。旋转的最终目的是将字符串 ring 的一个字符与 12:00 方向对齐,并且这个字符必须等于字符 key[i] 。
如果字符 key[i] 已经对齐到12:00方向,您需要按下中心按钮进行拼写,这也将算作 1 步。按完之后,您可以开始拼写 key 的下一个字符(下一阶段), 直至完成所有拼写。
/**
* @param {string} ring
* @param {string} key
* @return {number}
*/
var findRotateSteps = function (ring, key) {
// 外环编码相同字母索引放到同一数组
const ringMap = {};
for (let i = 0; i < ring.length; i++) {
const word = ring[i];
if (ringMap[word]) {
ringMap[word].push(i);
} else {
ringMap[word] = [i];
}
}
// 重复计算会超时 由于 1 <= ring.length, key.length <= 100 所以可以搞个备忘录
const memo = new Array(ring.length); // 相同编码索引开始,终点索引相同 直接取对应的最小步长
function bfs(ringIndex, keyIndex) {
if (keyIndex == key.length) return 0;
const stepMemo = memo[ringIndex]?.[keyIndex];
if (stepMemo) return stepMemo;
// 字母对应外编码多个位置的数组
const arr = ringMap[key[keyIndex]];
let minStep = Infinity;
// 找到这个字母不同位置、不同方向旋转最小的步长
for (let item of arr) {
// 同一个字母 不同方向移动步长
const l =
ringIndex - item >= 0
? ringIndex - item
: ringIndex - item + ring.length;
const r = ring.length - l;
// 不同旋转方向最小步长
const min = Math.min(l, r);
minStep = Math.min(minStep, min + bfs(item, keyIndex + 1));
}
memo[ringIndex] = { ...memo[ringIndex], [keyIndex]: minStep };
return minStep;
}
// 按下按钮需要一步,key个字母就是key.length
return key.length + bfs(0, 0);
};
给定一个非负整数数组 nums, nums 中一半整数是 奇数 ,一半整数是 偶数 。
对数组进行排序,以便当 nums[i] 为奇数时,i 也是 奇数 ;当 nums[i] 为偶数时, i 也是 偶数 。
你可以返回 任何满足上述条件的数组作为答案 。
/**
* @desc 使用额外内存
* @param {number[]} nums
* @return {number[]}
*/
var sortArrayByParityII = function (nums) {
const arr = [];
let even = 0;
let odd = 1;
for (let i = 0; i < nums.length; i++) {
if (nums[i] % 2 === 0) {
arr[even] = nums[i];
even += 2;
}else{
arr[odd] = nums[i];
odd += 2;
}
}
return arr;
};
/**
* @desc 不用额外空间
* @param {number[]} nums
* @return {number[]}
*/
var sortArrayByParityII = function (nums) {
let j = 1; // 奇数索引
for (let i = 0; i < nums.length - 1; i += 2) {
//数组中的偶数位置开始错误时
if (nums[i] % 2 !== 0) {
while (j < nums.length) {
if (nums[j] % 2 === 1) {
j += 2;
} else {
//奇数位置的值错误,和偶数错误值交换
[nums[i], nums[j]] = [nums[j], nums[i]];
j += 2;
break;
}
}
}
}
return nums;
};