天天一道算法题(第一期)

若是天天作一道算法题,那是否是天天都在进步?javascript

前言

这个活动是从2019年7月中旬开始的,人数不算多,也就几个好友和好友的好友,过程当中也会有人由于工做的缘故或其余缘由放弃,或许将来还会有人离开。php

活动的主要形式就是在leetcode刷题,每一个工做日一道题,每周作总结,目前已是第十二期,接下来我会把每期的题作一个总结,因为我是侧重javascript,因此活动中的每道题都是以js语言来实现解题方法。java

活动的规则比较严谨,群里天天早上10点以前发题,晚上10点审核,审核有管理员专门审核,称为打卡,没有打卡的人,须要发红包给管理员做为天天统计费用。群内不限制编程语言,目前已有Java、php、c等等。git

活动的目的就是培养算法思惟,了解常见的算法,好比分治算法、贪心算法、动态优化等等。算法

微信公众号惊天码盗同步第一期编程

两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。数组

  • 示例 1:
    输入: nums1 = [1,2,2,1], nums2 = [2,2]
    输出: [2,2]
    复制代码
  • 示例 2:
    输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
    输出: [4,9]
    复制代码

题解:微信

  • 替换法
    循环nums1,在循环中判断nums2中是否存在当前元素,若是存在就push到新的数组,而后在经过splice替换到当前元素,最后排序;编程语言

    执行用时:88ms;内存消耗:35.5MB;函数

    var intersect = function(nums1, nums2) {
        let arr = [];
        nums1.forEach((cur, i) => {
            if (nums2.indexOf(cur) > -1) {
                arr.push(cur)
                nums2.splice(nums2.indexOf(cur), 1, null)
            }
        })
        return arr.sort()
    }; 
    复制代码
  • 双指针法
    两个数组排序,设定两个为0的指针,比较两个指针的元素是否相等,若是相等,元素push到返回值里,两个指针同时往前,若是不相等,元素小的指针往前。

    执行用时:84ms;内存消耗:35MB;

    var intersect = function(nums1, nums2) {
        let p1 = 0
        let p2 = 0
        let res = []
        nums1 = nums1.sort((a, b) => a - b)
        nums2 = nums2.sort((a, b) => a - b)
        while(p1 < nums1.length && p2 < nums2.length) {
            if(nums1[p1] == nums2[p2]) {
                res.push(nums1[p1])
                p1++
                p2++
            } else if(nums1[p1] < nums2[p2]) {
                p1++
            } else {
                p2++
            }
        }
        return res
    }
    复制代码

1比特与2比特字符

有两种特殊字符。第一种字符能够用一比特0来表示。第二种字符能够用两比特(10 或 11)来表示。

现给一个由若干比特组成的字符串。问最后一个字符是否一定为一个一比特字符。给定的字符串老是由0结束。

  • 示例 1:
    输入: bits = [1, 0, 0]
    输出: True
    解释: 惟一的编码方式是一个两比特字符和一个一比特字符。因此最后一个字符是一比特字符。
    复制代码
  • 示例 2:
    输入: bits = [1, 1, 1, 0]
    输出: False
    解释: 惟一的编码方式是两比特字符和两比特字符。因此最后一个字符不是一比特字符。
    复制代码

题解:

  • 正则
    这是我见过最暴力直接的方式,由群内小伙伴提出的解题方式。

    执行用时:84ms;内存消耗:34.4MB;

    var isOneBitCharacter = function(bits) {
        return /^(10||11||0)*0$/.test(bits.join(""))
    };
    复制代码
  • 存储
    经过对象的方式;在循环中判断,若是遇到0、10或者11等状况添加到对象的属性上,这种方式能够有效的记录一共出现1比特和2比特出现的次数和顺序;最后判断最后一个比特是1比特仍是2比特。 执行用时:88ms;内存消耗:37.6MB;

    var isOneBitCharacter = function(bits) {
        let obj = {};
        let count = 1;
        bits.forEach((item, i) => {
            if (!obj[count]) obj[count] = [];
            if (obj[count].length >= 2) {count++; obj[count] = []};
            obj[count].push(item)
            if (obj[count][0] == 0 && i!=bits.length-1) count++;
        })
        return obj[count]&&obj[count][0] === 0 ? true : false
    };
    
    //对象结构以下
    //{
    // 1:[0],
    // 2:[1,1],
    // 3:[1,0],
    // ...
    //}
    复制代码
  • 跳针
    循环,遇1就++,若是++后跳出循环,就返回false,若是还在循环内,当循环到最后一个的时候返回true;

    执行用时:72ms;内存消耗:34.2MB;

    var isOneBitCharacter = function(bits) {
        let bitsSize = bits.length
        for (let i = 0; i < bitsSize; ++i) {
        if (i == bitsSize - 1) return true
        if (bits[i])++i;
        }
        return false;
    };
    复制代码

二进制求和

给定两个二进制字符串,返回他们的和(用二进制表示)。

输入为非空字符串且只包含数字 1 和 0。

  • 示例 1:
    输入: a = "11", b = "1"
    输出: "100"
    复制代码
  • 示例 2:
    输入: a = "1010", b = "1011"
    输出: "10101"
    复制代码

分析: 面对这道题,不少人立马想到的是2转10,而后转2,可是这会面临精度丢失的问题,若是解决了精度丢失的问题,那么也不失为一个好的解题方法。那么就只有一种方法那就是逐位相加法。

  • 补位法
    字符串转数组,而后翻转数组,取数组最长的length循环,在循环中数组短的自动补0,在循环中相加,判断相加为0或1或2的状况。而后push到新数组中,最后翻转,转成字符串。

    执行用时:108ms;内存消耗:35.6MB;(最笨的办法)

    var addBinary = function(a, b) {
        const alist=a.split('').reverse();
        const blist=b.split('').reverse();
        const arr=[];
        const len=alist.length>blist.length?alist.length:blist.length;
        for (let i = 0; i <= len-1; i++) {
            if (alist[i] != 0 && alist[i] != 1) {
                alist[i] = 0
            }
    
            if (blist[i] != 0 && blist[i] != 1) {
                blist[i] = 0
            }
            
            alist[i] = alist[i] - 0
            blist[i] = blist[i] - 0
    
            if (alist[i] + blist[i] > 1) {
                if (arr[i] == 0) {
                    arr[i] = 1
                } else if (arr[i] == 1) {
                    arr[i] = 1
                    arr.push(1)
                } else {
                    arr[i] = 0
                    arr.push(1)
                }
            }
            if (alist[i] + blist[i] == 1) {
                if (arr[i]) {
                    arr[i] = 0
                    arr.push(1)
                } else {
                    arr[i] = 1
                }
            }
            if (alist[i] + blist[i] == 0) {
                if (arr[i]) {
                    arr[i] = 1
                } else {
                    arr[i] = 0
                }
            }
        }
        return arr.reverse().join('')
    };
    复制代码
  • 进位拼接法
    与补位法相似,区别就是在进行计算时直接拼接字符串,会获得一个反向字符,须要最后再进行翻转;按照位置给结果字符赋值,最后若是有进位,则在前方进行字符串拼接添加进位。

    执行用时:112ms;内存消耗:35.9MB;(性能很差)

    var addBinary = function(a, b) {
        let ans = "";
        let ca = 0;
        for(let i = a.length - 1, j = b.length - 1;i >= 0 || j >= 0; i--, j--) {
            let sum = ca;
            sum += i >= 0 ? parseInt(a[i]) : 0;
            sum += j >= 0 ? parseInt(b[j]) : 0;
            ans += sum % 2;
            ca = Math.floor(sum / 2);
        }
        ans += ca == 1 ? ca : "";
        return ans.split('').reverse().join('');
    }
    复制代码

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。

你能够假设每种输入只会对应一个答案。可是,你不能重复利用这个数组中一样的元素。

  • 示例:
    给定 nums = [2, 7, 11, 15], target = 9
    由于nums[0] + nums[1] = 2 + 7 = 9
    因此返回 [0, 1]
    复制代码

题解:

  • 双循环法
    两层循环,外层取第一元素,内层取相加元素;

    执行用时:164ms;内存消耗:34.6MB;

    var twoSum = function(nums, target) {
        for (let i = 0; i < nums.length; i++) {
            for (let j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] === target) {
                    return [i, j]
                }
            }
        }
    };
    复制代码
  • 替换法
    复制原数组,循环原数组,防止重复,经过splice替换复制的数组,若是复制数组中存在相加元素,找到索引,便可获得结果数组。

    执行用时:304ms;内存消耗:36MB;

    var twoSum = function(nums, target) {
        let list = [...nums];
        let arr = []
        nums.forEach((item, i) => {
            list.splice(i, 1, null)
            const sum = target - item;
            if (list.includes(sum)) {
                arr = [i, list.indexOf(sum)].sort()
            }
        })
        return arr
    }
    复制代码
  • map
    经过新的数据类型Map来实现;

    执行用时:72ms;内存消耗:35.1MB;

    var twoSum = function(nums, target) {
        let map = new Map()
        for (let i = 0; i < nums.length; i++) {
            if (map.has(target - nums[i])) {
                return [map.get(target - nums[i]), i]
            }
            map.set(nums[i], i)
        }
    }
    复制代码

加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每一个元素只存储一个数字。

你能够假设除了整数 0 以外,这个整数不会以零开头。

  • 示例 1:
    输入: [1,2,3]
    输出: [1,2,4]
    解释: 输入数组表示数字 123复制代码
  • 示例 2:
    输入: [4,3,2,1]
    输出: [4,3,2,2]
    解释: 输入数组表示数字 4321复制代码

题解:

  • 递减相加
    循环递减,在循环中判断相加是否为10,若是为10,就把当前值改成0,下一值加一;

    执行用时:72ms;内存消耗:33.6MB;(性能很差)

    var plusOne = function(digits) {
        for(let i=digits.length-1;i>=0;i--){
            if(i==digits.length-1){
                digits[i]++
            }
            if(digits[i]==10){
                digits[i]=0
                if(i-1<0){
                    digits.unshift(1)
                }else{    
                    digits[i-1]++
                }
            }
        }
        return digits
    };
    复制代码
  • 条件
    for循环能够实现的,while也能够实现;

    执行用时:72ms;内存消耗:34.2MB;(性能很差)

    var plusOne = function(digits) {
        const values = digits.reverse();
        let i = 0;
        values[i] += 1;
        while (true) {
            if (values[i] >= 10) {
                values[i] = 0;
                if (values[i + 1] === undefined) {
                    values[i + 1] = 1;
                    break;
                } else {
                    values[i + 1] += 1
                }
                i++
            } else {
                break;
            }
        }
        return values.reverse()
    };
    复制代码

第一期结束,虽然坚持很累,加油!

若是你也想利用碎片时间来作这么一件事情,咱们能够监督你,二维码献上😊

相关文章
相关标签/搜索