js解leetcode(36)-中等

1.验证ip地址

题目:

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。

如果是有效的 IPv4 地址,返回 "IPv4" ;
如果是有效的 IPv6 地址,返回 "IPv6" ;
如果不是上述类型的 IP 地址,返回 "Neither" 。
IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;

同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。

IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如,  2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。

然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (::) 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。

同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

思路:split分割,然后手动遍历或者用正则都行。正则比较快

时间复杂度O(n),空间复杂度O(n)

/**
 * @param {string} IP
 * @return {string}
 */
var validIPAddress = function(IP) {
    const arrIp4 = IP.split('.');
    const arrIp6 = IP.split(":");
    const regIP4 = /^0$|^([1-9]\d{0,2})$/;
    const regIP6 = /^[0-9a-fA-F]{1,4}$/;
    if(arrIp4.length === 4) {
        if(arrIp4.every((item) => regIP4.test(item) && item < 256)) {
            return "IPv4";
        }
    } else if(arrIp6.length === 8) {
        if(arrIp6.every((item) => regIP6.test(item))) {
            return "IPv6";
        }
    } 
    return "Neither";

};

2.用Rand7()实现Rand10()

思路:拒绝采样或者分布计算都可以。

拒绝采样的意思,是先计算得到随机数,判断是否大于5,大于的话重新计算。然后,我们就均匀的得到了1-5的随机数。再取一次随机数,这次数字不能等于1或者7,然后我们得到了一个范围6的随机数,判断这个数在左区间还是右区间(比如舍弃7,左右区间就是1-3和2-6),左区间+0,右区间+5,这样就得到了一个1-10的随机数。(相当于随机了两次,一次随机是获取1-5的数,一次随机是随机+5)

/**
 * The rand7() API is already defined for you.
 * var rand7 = function() {}
 * @return {number} a random integer in the range 1 to 7
 */
var rand10 = function() {
  let result = rand7();
  while (result > 5) result = rand7();
  let temp = rand7();
  while (temp === 7) temp = rand7();
  return temp <= 3 ? result : result + 5;
};

3.火柴拼正方形

题目:

还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。

输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。

思路:先排除不可能的情况,比如总长不能被4整除。然后,对数组进行遍历,先声明一个set,记录当前数字可能组成的边长组合,在遍历数组的时候更新set,这样就能知道哪些长度是可以拼接起来的,然后判断1倍边长,2倍边长,3倍边长是否在set里存在,存在就说明正方形可以得到

时间复杂度O(nlogn),空间复杂度O(nlogn)

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var makesquare = function(nums) {
  const l = nums.length;
  if (l < 4) return false;
  const sum = nums.reduce((a, b) => a + b);
  if (sum % 4) return false;
  nums.sort((a, b) => a - b);
  let curSum = 0;
  const num = sum / 4;
  if (num < nums[l - 1]) return false;
  if (nums[l - 1] < num && nums[0] + nums[l - 1] > num) return false;
  let set = new Set();
  for (const item of nums) {
    const temp = new Set();
    temp.add(item);
    for (const v of set) {
      temp.add(v + item);
      temp.add(v);
    }
    set = temp;
  }
  return set.has(num) && set.has(2 * num) && set.has(3 * num);
};

4.一和零

思路:

给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

思路:背包问题。可以建立m*n的二维数组,dp[i,j]就是i个0和j个1时容纳的最大子集的数量,有:

dp[i][j]=Math.max(dp[i,j],dp[m-i][n-j] + 1)

遍历数组时不断更新dp[i,j]的值

时间复杂度O(mnl),空间复杂度O(mn)

/**
 * @param {string[]} strs
 * @param {number} m
 * @param {number} n
 * @return {number}
 */
var findMaxForm = function(strs, m, n) {
  const l = strs.length;
  const valueList = strs.map((item) => {
    let v0 = 0,
      v1 = 0;
    for (let i = 0; i < item.length; i++) {
      if (item[i] == "0") {
        v0++;
      } else {
        v1++;
      }
    }
    return [v0, v1];
  });
  const dp = new Array(m + 1).fill("").map(() => new Array(n + 1).fill(0));
  for (let i = 0; i < l; i++) {
    const [v0, v1] = valueList[i];
    for (let j = v0; j <= m; j++) {
      for (let k = v1; k <= n; k++) {
        dp[j][k] = Math.max(dp[j][k], dp[m - j][n - k] + 1);
      }
    }
  }
  return dp[m][n];
};

5.汉明距离总和

题目:

两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。

计算一个数组中,任意两个数之间汉明距离的总和。

思路:因为数组成员转成二进制之后,长度不一样,所以先对二进制字符串前缀补0,补全到32位长度,(最大成员的值小于这个值即可)

然后,可以记录每一位的0和1的数量,那么这一位的汉明距离就是两者的乘积。最后累加

时间O(n),空间复杂度O(1)

/**
 * @param {number[]} nums
 * @return {number}
 */
var totalHammingDistance = function(nums) {
  const l = nums.length;
  const v0 = new Array(32).fill(0);
  const v1 = new Array(32).fill(0);
  for (let i = 0; i < l; i++) {
    const v = nums[i].toString(2).padStart(32, "0");
    for (let i = 0; i < 32; i++) {
      if (v[i] == "1") {
        v1[i]++;
      } else {
        v0[i]++;
      }
    }
  }
  let res = 0;
  for (let i = 0; i < 32; i++) {
    res += v0[i] * v1[i];
  }
  return res;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值