两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。我们可以不考虑输出结果的顺序。

示例:

输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]

输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
  • 方法一:数组切割处理
//执行用时 :64 ms, 在所有 javascript 提交中击败了91.85%的用户
//内存消耗 :33.8 MB, 在所有 javascript 提交中击败了86.17%的用户
var intersect = function(nums1, nums2) {
  var res = [];
  //包含之后再清除
  for(var i=0;i<nums1.length;i++){
      if(nums2.includes(nums1[i])){
          res.push(nums1[i]);
          nums2.splice(nums2.indexOf(nums1[i]), 1);
      }
  }
  return res;
};

//执行用时 :72 ms, 在所有 javascript 提交中击败了66.52%的用户
//内存消耗 :33.9 MB, 在所有 javascript 提交中击败了72.60%的用户
var intersect = function (nums1, nums2) {
  return nums1.filter(el => nums2.includes(el) && nums2.splice(nums2.indexOf(el), 1))
};
  • 方法二:字典

多加了记录元素个数的功能,我们可以使用字典 dict 实现它

//执行用时 :76 ms, 在所有 javascript 提交中击败了52.47%的用户
//内存消耗 :34.7 MB, 在所有 javascript 提交中击败了50.79%的用户
var intersect = function (nums1, nums2) {
  var len1 = nums1.length;
  var len2 = nums2.length;
  if (len1 === 0 || len2 === 0) {
    return [];
  }

  var dict1 = {};
  var result = [];
  nums1.forEach((item, index) => {
    if (dict1.hasOwnProperty(item)) {
      dict1[item] += 1;
    } else {
      dict1[item] = 1;
    }
  })

  nums2.forEach((item) => {
    if (dict1.hasOwnProperty(item) && dict1[item] > 0) {
      result.push(item);
      dict1[item] -= 1;
    }
  })

  return result;
}

// 执行用时 :68 ms, 在所有 javascript 提交中击败了82.19%的用户
// 内存消耗 :36 MB, 在所有 javascript 提交中击败了12.23%的用户
var intersect = function (nums1, nums2) {
  var obj1 = arrChange(nums1);
  var obj2 = arrChange(nums2);
  var res = [];
  for (var pro in obj1) {
    if (obj2.hasOwnProperty(pro)) {
      obj1[pro].length < obj2[pro].length ? res.push(...obj1[pro]) : res.push(...obj2[pro]);
    }
  }
  return res;
};

function arrChange(arr) {
  var obj = {};
  arr.forEach((item, index) => {
    if (obj.hasOwnProperty(item)) {
      obj[arr[index]].push(item);
    } else {
      obj[arr[index]] = [item];
    }
  })
  return obj;
}
有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词

示例:

输入: s = "anagram", t = "nagaram"
输出: true

输入: s = "rat", t = "car"
输出: false
  • 方法一:字典对各个字符出现的次数进行统计
var isAnagram = function (s, t) {
  if (s.length != t.length) {
    return false;
  }

  var calT = cal(t);
  for (var ele of s) {
    if (!t.includes(ele) || calT[ele] == 0) {
      return false;
    }
    calT[ele]--;
  }
  return true;
};

function cal(str) {
  var times = {};
  for (var ele of str) {
    if (times.hasOwnProperty(ele)) {
      times[ele]++;
    } else {
      times[ele] = 1;
    }
  }
  return times;
}
  • 方法二:转换成数组排序后对比
//执行用时 :116 ms, 在所有 javascript 提交中击败了48.25%的用户
//内存消耗 :38.6 MB, 在所有 javascript 提交中击败了28.30%的用户
var isAnagram = function (s, t) {
  return JSON.stringify(s.split('').sort()) === JSON.stringify(t.split('').sort());
};


//执行用时 :132 ms, 在所有 javascript 提交中击败了26.88%的用户
//内存消耗 :38.1 MB, 在所有 javascript 提交中击败了43.10%的用户
var isAnagram = function (s, t) {
  return s.split('').sort().join('') === t.split('').sort().join('')
};

var isAnagram = function (s, t) {
  const sort = str => [...str]
    .sort((a, b) => a.charCodeAt() - b.charCodeAt())
    .join('')
  return sort(s) === sort(t)   //如果输入字符串包含 unicode 字符
};
同构字符串

给定两个字符串 s 和 t,判断它们是否是同构的。如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。

示例:

输入: s = "egg", t = "add"
输出: true

输入: s = "foo", t = "bar"
输出: false

输入: s = "paper", t = "title"
输出: true
  • 比较每个字符下一次出现位置是否一致
//执行用时 :60 ms, 在所有 javascript 提交中击败了99.19%的用户
//内存消耗 :35.3 MB, 在所有 javascript 提交中击败了66.33%的用户
var isIsomorphic = function (s, t) {
  if (s.length != t.length) {
    return false;
  }

  for (let i = 0; i < s.length; i++) {
    if (s.indexOf(s[i], i + 1) !== t.indexOf(t[i], i + 1)) {
      return false;
    }
  }
  return true;
};
  • 哈希,记录两个字符串中的被替换字符和替换字符,判断是否是唯一
//执行用时 :72 ms, 在所有 javascript 提交中击败了81.91%的用户
//内存消耗 :35.2 MB, 在所有 javascript 提交中击败了74.49%的用户
var isIsomorphic = function (s, t) {
  if (s.length !== t.length) return false;
  let hashOne = {}, hashTwo = {}, len = s.length;
  for (let i = 0; i < len; i++) {
    let a = s[i], b = t[i];
    if (!hashOne[a] && !hashTwo[b]) {
      hashOne[a] = b;
      hashTwo[b] = a;
    } else if (hashOne[a] !== b || hashTwo[b] !== a) {
      return false;
    }
  }
  return true;
};


//执行用时 :80 ms, 在所有 javascript 提交中击败了54.02%的用户
//内存消耗 :35.8 MB, 在所有 javascript 提交中击败了48.98%的用户
var isIsomorphic = function (s, t) {
  //同构则说明能相互转化
  var map = new Map();
  var map2 = new Map();
  for (var i = 0; i < s.length; i++) {
    map.set(s[i], t[i]);
    map2.set(t[i], s[i])
  }
  for (var j = 0; j < s.length; j++) {
    if (map.get(s[j]) !== t[j]) {
      return false;
    }
    if (map2.get(t[j]) !== s[j]) {
      return false;
    }
  }
  return true;
};
  • 数组,判断被替换字符与替换字符一一对应
//执行用时 :68 ms, 在所有 javascript 提交中击败了89.95%的用户
//内存消耗 :35.7 MB, 在所有 javascript 提交中击败了51.02%的用户
var isIsomorphic = function(s, t) {
  var a=[],l=[];
  if(s.length==0){
      return true;
  }
  for(var i=0;i<s.length;i++){
      if(s[i] in a){
          if(a[s[i]]!==t[i]){  //已经替换过的情况下,被替换字符与替换字符唯一对应
              return false;
          }
      }else{
          if(l.indexOf(t[i])!==-1){  //替换字符唯一
              return false;
          }
          a[s[i]]=t[i];
          l.push(t[i]);
      }
  }
  return true;
};
根据字符出现频率排序

给定一个字符串,请将字符串里的字符按照出现的频率降序排列

示例:

输入:
"tree"

输出:
"eert"

解释:
'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。


输入:
"Aabb"

输出:
"bbAa"

解释:
此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意'A'和'a'被认为是两种不同的字符。
  • map
//执行用时 :76 ms, 在所有 javascript 提交中击败了96.69%的用户
//内存消耗 :38.4 MB, 在所有 javascript 提交中击败了54.05%的用户
var frequencySort = function(str) {
  let map = new Map()
  let result = ''
  str.split('').forEach(item => {
    if (map.has(item)) {
      map.set(item, map.get(item) + 1)
    } else {
      map.set(item, 1)
    }
  })
  map = [...map]
    .sort((a, b) => b[1] - a[1])
    .map(item => {
      result += item[0].repeat(item[1])
    })
  return result
}

//执行用时 :136 ms, 在所有 javascript 提交中击败了7.28%的用户
//内存消耗 :44 MB, 在所有 javascript 提交中击败了24.32%的用户
var frequencySort = function (s) {
  const sArr = [...s];
  const record = new Map();

  sArr.forEach(value => {
    record.set(value, (record.get(value) || 0) + 1)
  })
  return sArr.sort((a, b) => record.get(b) == record.get(a) ? a.charCodeAt(0) - b.charCodeAt(0) : record.get(b) - record.get(a)).join('');
};
  • 字典
//执行用时 :100 ms, 在所有 javascript 提交中击败了40.40%的用户
//内存消耗 :44.6 MB, 在所有 javascript 提交中击败了10.81%的用户
var frequencySort = function (s) {
  var calTimes = {};
  for (let str of s) {
    if (!calTimes.hasOwnProperty(str)) {
      calTimes[str] = 1;
    } else {
      calTimes[str]++;
    }
  }

  var sortStr = sortObj(calTimes);
  var res = '';
  sortStr.forEach((key) => {
    while (calTimes[key] > 0) {
      res += key;
      calTimes[key]--;
    }
  })
  return res;
}

function sortObj(obj) {
  return Object.keys(obj).sort((a, b) => {
    return obj[b] - obj[a];
  })
}