JS算法之第一个只出现一次的字符及数组中对逆序对

333 阅读2分钟

这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

第一个只出现一次的字符

剑指Offer 50.第一个只出现一次的字符

难度:简单

题目:leetcode-cn.com/problems/di…

在字符串s中找出第一个只出现一次的字符。如果没有,返回一个单空格。s只包含小写字母。

示例:

s = "abaccdeff"
返回 "b"

s = "" 
返回 " "

限制: 0 <= s的长度 <= 50000

题解

法一 使用api函数

使用indexOf和lastIndexOf巧妙解决问题。

/**
 * @param {string} s
 * @return {character}
 */
var firstUniqChar = function (s) {
  for (let x of s) {
    if (s.indexOf(x) === s.lastIndexOf(x)) {
      return x;
    }
  };
  return ' ';
};

法二 哈希表

步骤:

  • 对字符串进行循环,如果字符第一次出现,则在哈希表中对其置1,如果不是第一次出现的话则进行累加。
  • 遍历哈希表,返回第一个出现次数为1的字符。
var firstUniqChar = function (s) {
  if(!s) return ' ';
  let dic = new Map();
  for (let c of s) {
    if (dic.has(c)) {
      dic.set(c, dic.get(c) + 1)
    } else {
      dic.set(c, 1);
    }
  }

  for (let x of dic.keys()) {
    if (dic.get(x) === 1) {
      return x;
    }
  }
  return ' ';
};
  • 时间复杂度:O(NN)
  • 空间复杂度:O(NN)

数组中的逆序对

剑指Offer 51.数组中对逆序对

难度:困难

题目:leetcode-cn.com/problems/sh…

在数组的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例1:

输入: [7,5,6,4]
输出: 5

限制:0 <= 数组长度 <= 50000

题解

法一 暴力法

两层for循环去检查是否为逆序对。

var reversePairs = function (nums) {
  let sum = 0;
  const len = nums.length;

  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      nums[i] > nums[j] && sum++;
    }
  }
  return sum;
}
  • 时间复杂度:O(N2N^2)
  • 空间复杂度:O(11)

法二 归并排序

能够看到非常明显的阶段排序结果的算法就是归并排序,采用分而治之的思想:

  • 将数组不断的进行一拆二,拆到每个数组中只有一个元素为止
  • 对每个数组两两进行合并,其中每个数组内都是有序的

对于本题:

先设置一个sum来记录逆序对个数,采用归并排序的方式,在合并时,设置i和j分别对应两个合并数组的左部分left和右部分right,当left[i] > right[j]时说明当前[i, left.length]的值均大于right[j],因此均可以作为逆序对,故sum += left.length - i

var reversePairs = function (nums) {
  let sum = 0;
  mergeSort(nums);
  return sum;

  function mergeSort(nums) {
    if (nums.length < 2) return nums;
    const mid = Math.floor(nums.length / 2);
    let left = nums.slice(0, mid);
    let right = nums.slice(mid);
    return merge(mergeSort(left), mergeSort(right));
  }

  function merge(left, right) {
    let res = [];
    let lLen = left.length;
    let rLen = right.length;
    let Len = lLen + rLen;

    for (let index = 0, i = 0, j = 0; index < Len; index++) {
      if (i >= lLen) res[index] = right[j++]; // i遍历完了
      else if (j >= rLen) res[index] = left[i++]; // j遍历完了
      else if (left[i] <= right[j]) res[index] = left[i++]; 
      else {
        res[index] = right[j++];
        sum += lLen - i;
      }
    }
    return res;
  }
} 
  • 时间复杂度:O(NlogNNlogN)
  • 空间复杂度:O(NN)

坚持每日一练!前端小萌新一枚,希望能点个哇~