一天一大 leet(计算右侧小于当前元素的个数)难度:困难-Day20200711

img

题目:

给定一个整数数组 nums,按要求返回一个新数组 counts。
数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

示例
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.

抛砖引玉

img

暴力循环
  • 声明一个存储结果的数组填充默认值 0
  • 逆向遍历输入数字
  • 对每个数组指定循环之后的数统计比其小的数字个数存储到存储结果的数组中
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var countSmaller = function (nums) {
  let len = nums.length,
    _result = Array(len).fill(0)
  for (let i = len - 1; i >= 0; i--) {
    _result[i] = get_num(i, nums, nums[i])
  }
  function get_num(start, nums, n) {
    let num = 0
    if (start === nums.length - 1) return num
    for (let i = start; i <= nums.length - 1; i++) {
      if (nums[i] < n) num++
    }
    return num
  }
  return _result
}

不是吧
这样一道困难的题就完了,没那么简单,优化下吧

二分法查找

思路

上面的循环会发现i越小循环的次数越多,而且对右边一个数的比较越多
最后一位数需要参与len-1次比较

  • 如果能记录每一个位置的依次小于它的数,循环时我们只要知道新加入在哪两个数之间就可以之间得到它的结果
  • 查询一个数在哪两个数之间就演化成了排序的问题
  • 在一个数组里面最快定位一个数的位置,最快为:数组有序,二分法
    则,逻辑就变成了:从nums从右向左取出元素到新数组排序,并且记录每一个数的位置

实现

  • 依次取出nums到一个新数字
  • 新数组为排序数组
  • 设取到nums[i],项新数组中插入时需要知道插入位置,插入位置即要求的右侧小于它的数
  • 插入是数据越多循环查询位置的次数越多,优化循环,借助二分法的思路求要插入的数据在新数组中的插入位置
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var countSmaller = function (nums) {
  let len = nums.length
  if (len == 0) return nums
  let _result = Array(len).fill(0),
    dp = [];
  for (let i = len - 1; i >= 0; i--) {
    // 计算位置
    let index = findIndex(dp, nums[i])
    // 插入数据
    dp.splice(index, 0, nums[i])
    // 记录索引
    _result[i] = index
  }
  function findIndex(arr, target) {
    let start = 0,
        end = arr.length - 1;
    while (start < end) {
      let mid = parseInt((start + end) / 2,10)
      if (arr[mid] < target) {
        start = mid + 1;
      } else {
        end = mid;
      }
    }
    if (arr[start] < target) return start + 1;
    return start
  }
  return _result
}

博客: 小书童博客

公号: 坑人的小书童

坑人的小书童

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探险家小扣的行动轨迹,都将保存在记录仪中。expeditions[i] 表示小扣第 i 次探险记录,用一个字符串数组表示。其中的每个「营地」由大小写字母组成,通过子串 -> 连接。例:"Leet->code->Campsite",表示到访了 "Leet"、"code"、"Campsite" 三个营地。expeditions[0] 包含了初始小扣已知的所有营地;对于之后的第 i 次探险(即 expeditions[i] 且 i > 0),如果记录中包含了之前均没出现的营地,则表示小扣 发现 的营地。 请你找出小扣发现营地最多且索引最小的那次探险,并返回对应的记录索引。如果所有探险记录都没有发现的营地,返回 -1。注意: 大小写不同的营地视为不同的营地; 营地的名称长度均大于 0。用python实现。给你几个例子:示例 1: 输入:expeditions = ["leet->code","leet->code->Campsite->Leet","leet->code->leet->courier"] 输出:1 解释: 初始已知的所有营地为 "leet" 和 "code" 第 1 次,到访了 "leet"、"code"、"Campsite"、"Leet",发现营地 2 处:"Campsite"、"Leet" 第 2 次,到访了 "leet"、"code"、"courier",发现营地 1 处:"courier" 第 1 次探险发现的营地数量最多,因此返回 1。示例 2: 输入:expeditions = ["Alice->Dex","","Dex"] 输出:-1 解释: 初始已知的所有营地为 "Alice" 和 "Dex" 第 1 次,未到访任何营地; 第 2 次,到访了 "Dex",未发现营地; 因为两次探险均未发现的营地,返回 -1
最新发布
04-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值