「leetcode」561. 数组拆分 I;796. 旋转字符串;189. 旋转数组;459. 重复的子字符串;575. 分糖果

560 阅读4分钟

前言

一些水题,gaga~~

561. 数组拆分 I

原题

给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。

示例 1:

输入: [1,4,3,2]

输出: 4
解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4)

思路

水题,在对数组内容进行分对的时候,并不需要考虑数组的顺序。所以,只需将数组从小到大进行排序,然后取数组中的所有偶数位即可。

代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var arrayPairSum = function(nums) {
    let result = 0
    nums = nums.sort((a, b) => a - b)
    for (let i = 0; i < nums.length; i+=2) {
        result += nums[i]
    }
    return result
};

796. 旋转字符串

原题

给定两个字符串, A 和 B。

A 的旋转操作就是将 A 最左边的字符移动到最右边。 例如, 若 A = 'abcde',在移动一次之后结果就是'bcdea' 。如果在若干次旋转操作之后,A 能变成B,那么返回True。

示例 1:

输入: A = 'abcde', B = 'cdeab'
输出: true

示例 2:

输入: A = 'abcde', B = 'abced'
输出: false

思路

举两个例子

// 例子1
var a = 'abcde'
var a2 = 'abcdeabcde' // a + a
a2.includes('cdeab') // true

// 例子2
var b = 'abcde'
var b2 = 'abcdeabcde'
b2.includes('abced') // false

如果B字符串由A字符串旋转而来,那么B字符串必然会出现在,两个A字符串相连形成的新字符串S中。

代码

/**
 * @param {string} A
 * @param {string} B
 * @return {boolean}
 */
var rotateString = function(A, B) {
    return A.length === B.length && ~(A + A).indexOf(B)
};

189. 旋转数组

原题

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释: 
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]

思路

当k大于nums的长度时,那么k中只有k % nums.length次是有效的旋转,因为在旋转nums.length次时,数组就会重新回到初始的状态。我们在排除这些无用的旋转后,可避免当k过大时运行超时问题。

代码

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var rotate = function(nums, k) {
    const len = nums.length
    
    if (k > len) {
        k = k % len
    }
    
    while (k > 0) {
        let last = nums.pop()
        nums.unshift(last)
        k--
    }
    
    return nums
};

459. 重复的子字符串

原题

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1:

输入: "abab"

输出: True

解释: 可由子字符串 "ab" 重复两次构成。

示例 2:

输入: "aba"

输出: False

示例 3:

输入: "abcabcabcabc"

输出: True

解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

思路

举两个例子

// 例子1
var a = 'abab'
var a2 = 'abababab' // a + a
a2.indexOf(a, 0) // 0
a2.indexOf(a, 1) // 2
a2.indexOf(a, 3) // 4

当一个字符串A是由它的一个子串重复多次构成时,那么两个字符串A相加形成的新字符串S中,至少包含3次的A

QQ20191020-144451@2x.png

代码

/**
 * @param {string} s
 * @return {boolean}
 */
var repeatedSubstringPattern = function(s) {
    return (s + s).indexOf(s, 1) !== s.length
};

575. 分糖果🍬

原题

给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果。你需要把这些糖果平均分给一个弟弟和一个妹妹。返回妹妹可以获得的最大糖果的种类数。

示例 1:

输入: candies = [1,1,2,2,3,3]
输出: 3
解析: 一共有三种种类的糖果,每一种都有两个。
     最优分配方案:妹妹获得[1,2,3],弟弟也获得[1,2,3]。这样使妹妹获得糖果的种类数最多。

示例 2 :

输入: candies = [1,1,2,3]
输出: 2
解析: 妹妹获得糖果[2,3],弟弟获得糖果[1,1],妹妹有两种不同的糖果,弟弟只有一种。这样使得妹妹可以获得的糖果种类数最多。

注意:

  • 数组的长度为[2, 10,000],并且确定为偶数。
  • 数组中数字的大小在范围[-100,000, 100,000]内。

思路

对数组进行去重后得到的数组的长度,既是糖果种类的长度。

如果糖果种类的长度,大于全部糖果数量的一半,妹妹可以最多获得糖果数量 / 2种类的糖果。

如果糖果种类的长度,小于全部糖果数量的一半,妹妹可以获得全部种类的糖果。

代码


/**
 * @param {number[]} candies
 * @return {number}
 */
var distributeCandies = function(candies) {
    const k = new Set(candies).size
    return k > candies.length / 2 ? candies.length / 2 : k
};