牛客网剑指offer66道题(JS实现,部分题目含思路及拓展方法,持续更新)

本文汇总了牛客网剑指Offer的66道编程题,涉及数组查找、字符串处理、链表操作、递归计算等多个方面。题目包括二维数组查找、替换空格、从尾到头打印链表、计算数列和、二进制表示中1的个数、逆序对统计等。每道题均提供了JS实现和解题思路,部分题目还包含了拓展方法和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题1】二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路:(1)矩阵是有序的,从左向右递增,从上向下递减;

           (2)从左下角开始查找,比目标值大的,向上找;比目标值小的,向右找。

function Find(target, array)
{
    let rows = array.length;
    let columns = array[0].length;
    for (var j = 0, i = rows - 1; i  >= 0 && j < columns;) {
        if (array[i][j] == target) {
            return true
        } else if (array[i][j] > target) {
            i--;
            continue
        } else if (array[i][j] < target) {
            j++
            continue
        }
    }
    return false
}

【题2】替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

function replaceSpace(str)
{
    // 首先将字符串转换为数组["We", "Are", "Happy"]
    let array = str.split(' ')
    for (var i = 0; i < array.length - 1; i++) {
        // 将%20添加进去["We%20", "Are%20", "Happy"]
        array[i] = array[i] + "%20" 
    }
    // 数组转换为字符串
    let arr = array.join('')
    return arr
}

牵扯到一个问题,使用正则表达式将逗号删除

function replaceSpace(str)
{
    // 首先将字符串转换为数组["We", "Are", "Happy"]
    let array = str.split(' ')
    for (var i = 0; i < array.length - 1; i++) {
        // 将%20添加进去["We%20", "Are%20", "Happy"]
        array[i] = array[i] + "%20," 
    }
    // 数组转换为字符串
    let arr = array.join('')
    // 由于字符串中带了逗号We%20,Are%20,Happy,使用正则表达式将逗号删除We%20Are%20Happy
    array = arr.replace(/^,/g,'')
    return array
}

其他人的好的方式

// \s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
// 直接遍历字符串,遇到空格就替换。
return str.replace(/\s/g,'%20')


return str.split(" ").join("%20")

【题3】从尾到头打印链表

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function printListFromTailToHead(head)
{
    let array = []
    let start = head
    while(start) {
        array.push(start.val)
        start = start.next
    }
    return array.reverse()
}

【题4】计算1+2+3+…………+n

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

基于此,采用短路求值原理:

“||”运算符表示或,有一个为真则结果为真,前半部分判断出为真之后,不用继续考虑后半部分,最终结果为真;

“&&”运算符表示与,有一个为假则结果为假,前半部分判断出为假之后,不用考虑后半部分,最终结果为假。

利用上述原理,可以进行递归运算。

function Sum_Solution(n)
{
    var ans = n
    ans && (ans += Sum_Solution(n-1))
    return ans
}

【题5】写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

  1. 两个数异或:相当于每一位相加,而不考虑进位;
  2. 两个数相与,并左移一位:相当于求得进位;
  3. 将上述两步的结果相加
function Add(num1, num2)
{
    while(num2 != 0) {
        var sum = num1 ^ num2 // 两数相加,不考虑进位
        var num3 = (num1&num2) << 1 // 进位
        num1 = sum
        num2 = num3
    }
    return num1
}

13+11 = ?; 

13 的二进制      1 1 0 1                     -----a        13 

11 的二进制      1 0 1 1                     -----b        11   

 

 (a&b)<<1  ->  1 0 0 1 0                   -----d         18

          a^b  ->     0 1 1 0                   -----e          6 

 

 (d&e)<<1  ->  0 0 1 0 0                  ------f         4

          d^e  ->  1 0 1 0 0                  -----g        20

 

 (f&g)<<1  ->  0 10 0 0                  ------h        8

          f^g  ->  1 0 0 0 0                  ------i          16

 

 (h&i)<<1  ->  0 0 0 0 0                  ------h        0       ------------退出循环

          h^i  ->  1 1 0 0 0                 ------i          24

【题6】输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

function NumberOf1(n)
{
    //js中负数使用二进制补码的形式存储
    if (n<0) {
        //无符号右移将负数的二进制码当成正数的二进制码
        n = n >>> 0
    }
    // n.toString(2)转化成二进制数,n.toString(2).split('1'),n为16打印结果["", "00000"]
    var arrN = n.toString(2).split('1')
    return arrN.length-1
}

【题7】在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

function duplicate(numbers, duplication)
{
    //这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    //函数返回True/False
    if (numbers.length === 0 || numbers.length ===1) {
        return false
    }
    for (var i = 0; i < numbers.length -1; i++) {
        for (var j = numbers.length-1; j > i; j--) {
            if (numbers[i] === numbers[j]) {
                duplication[0] = numbers[i]
                return true
            }
        }
    }
    return false
}

【题8】给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

function Power(base, exponent)
{
    return Math.pow(base, exponent)
}
function Power(base, exponent)
{
    return base**exponent
}

【题9】斐波那契数列

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 

n<=39

斐波那契数列:兔子数列

在第一个月有一对刚出生的小兔子,在第二个月小兔子变成大兔子并开始怀孕,第三个月大兔子会生下一对小兔子,并且以后每个月都会生下一对小兔子。 如果每对兔子都经历这样的出生、成熟、生育的过程,并且兔子永远不死,那么兔子的总数是如何变化的?

我们把这个数列列表

我们发现会发现以下几个规律:

前一个月的大兔子对数就是下一个月的小兔子对数。前一个月的大兔子和小兔子对数的和就是下个月大兔子的对数。

按照这个表格,我们会发现无论是小兔子对数、大兔子对数还是总对数,除了最初几个数字不一样之外,后面都是按照1、1、2、3、5、8、13…变化的,这个数列就称为兔子数列或者斐波那契数列。

兔子数列最大的特点就是前两项之和等于后一项,比如1+1=2、1+2=3、2+3=5、3+5=8、5+8=13…

我们用an表示一个数列的第n项,那么斐波那契数列的规律就是

这种式子称为递推式,也就是说可以从前面一项或几项,计算出后面一项的式子。再结合前两项a1=a2=1,就可以得到后面任意一项了。

function Fibonacci(n)
{
    if (n === 0) {
        return 0
    }
    if (n === 1 || n === 2) {
        return 1
    }
    return Fibonacci(n-1) + Fibonacci(n-2)
}
function Fibonacci(n)
{
    if (n === 0) {
        return 0
    }
    if (n === 1 || n === 2) {
        return 1
    }
    if (n === 3) {
        return 2
    }
    return 3*Fibonacci(n-3) + 2*Fibonacci(n-4)
}

【题】一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

function jumpFloor(number)
{
    if(number === 0) {
        return 0
    } else if (number === 1) {
        return 1
    } else if (number === 2) {
        return 2
    }
    var arr = []
    arr[0] = 1
    arr[1] = 1
    arr[2] = 2
    for (var i = 3; i <= number; i++) {
        arr[i] = arr[i - 1] + arr[i - 2]
    }
    return arr[number]
}

 【题】一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

function jumpFloorII(number)
{
    if (number === 0) {
        return 0
    } else if (number === 1) {
        return 1
    } else if (number === 2) {
        return 2
    } else {
        return 2*jumpFloorII(number-1)
    }
}

【题10】旋转数组的最小数

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

function minNumberInRotateArray(rotateArray)
{
    if (rotateArray.length === 0) {
        return 0
    }
    for (var i = 0; i < rotateArray.length - 1; i++) {
        for (var j = 0; j < rotateArray.length - i - 1; j++) {
            if (rotateArray[j] > rotateArray[j+1]) {
                var tmp = rotateArray[j]
                rotateArray[j] = rotateArray[j+1]
                rotateArray[j+1] = tmp
            }
        }
    }
    return rotateArray[0]
}
function minNumberInRotateArray(rotateArray)
{
    if (rotateArray.length === 0) {
        return 0
    }
    rotateArray.sort(function (a, b) {
        return a-b
    })
    return rotateArray[0]
}

【题11】数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:

题目保证输入的数组中没有的相同的数字

数据范围:

对于%50的数据,size<=10^4

对于%75的数据,size<=10^5

对于%100的数据,size<=2*10^5

首先,我想到的是挨个遍历的方式,毫无疑问,在数组长度较大的时候,会出现运行时间慢的问题,且复杂度高,导致运行不通过。代码如下:

function InversePairs(data)
{
    // write code here
    var count = 0
    for (var i = 0; i < data.length; i++) {
        for (var j = i+1; j < data.length; j++) {
            if (data[i] > data[j]) {
                count++
            }
        }
    }
    return count%1000000007
}

不通过

您的代码已保存
运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为50.00%

另:基于归并排序的方式,

归并排序代码如下:

function merge(left, right){
    var result=[];
    while(left.length>0 && right.length>0){
        if(left[0]<right[0]){
            /*shift()方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。*/
            result.push(left.shift());
        }else{
            result.push(right.shift());
        }
    }
    return result.concat(left).concat(right);
}
function mergeSort(items){
    if(items.length == 1){
        return items;
    }
    var middle = Math.floor(items.length/2),
        left = items.slice(0, middle),
        right = items.slice(middle);
    return merge(mergeSort(left), mergeSort(right));
}
var items = [5,6,2,1,3,8,1,9,6,100]
document.write(mergeSort(items))

下述方式是基于归并排序,可顺利通过:

先把数组分割成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对的过程中,还需要对数组进行排序。

function InversePairs(data)
{
    if(!data || data.length < 2) return 0;
 
    var copy = data.slice(),
        count = 0;
    count = mergeSort(data, copy, 0, data.length-1);
    return count%1000000007;
}
 
function mergeSort(data, copy, start, end){
    if(end === start) return 0;
    var mid = (end-start)>>1,
        left = mergeSort(copy, data, start,start + mid),
        right = mergeSort(copy, data, start + mid + 1, end),
        count = 0,
        p = start + mid,//前一个数组的最后一个下标
        q = end,//后一个数组的下标
        copyIndex = end;//辅助数组下标,从最后一个算起
 
    while(p >= start && q >= start + mid + 1){
        if(data[p] > data[q]){
            count += q - start - mid;
            copy[copyIndex--] = data[p--];
        }else{
            copy[copyIndex--] = data[q--];
        }
    }
 
    while(p >= start){
        copy[copyIndex--] = data[p--];
    }
 
    while(q>=start+mid+1){
        copy[copyIndex--] = data[q--];
    }
    return left+right+count;
}

【题12】字符串的排列(本题知识点:字符串、动态规划、递归)

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

方法一:递归算法

/*思路:递归法,问题转换为先固定第一个字符,求剩余字符的排列;求剩余字符排列时跟原问题一样。
            (1) 遍历出所有可能出现在第一个位置的字符(即:依次将第一个字符同后面所有字符交换);
            (2) 固定第一个字符,求后面字符的排列(即:在第1步的遍历过程中,插入递归进行实现)。
            需要注意的几点:
            (1) 先确定递归结束的条件,例如本题中可设begin == str.size() - 1;
            (2) 形如 aba 或 aa 等特殊测试用例的情况,vector在进行push_back时是不考虑重复情况的,需要自行控制;
            (3) 输出的排列可能不是按字典顺序排列的,可能导致无法完全通过测试用例,考虑输出前排序,或者递归之后取消复位操作。*/

https://blog.youkuaiyun.com/wzy_1988/article/details/8939140

这是典型的递归求解问题,递归算法有四个特性:
       必须有可达到的终止条件,否则程序陷入死循环
       子问题在规模上比原问题小
       子问题可通过再次递归调用求解
       子问题的解应能组合成整个问题的解

对于字符串的排列问题:
如果能生成n-1个元素的全排列,就能生成n个元素的全排列。对于只有一个元素的集合,可以直接生成全排列。所以全排列的递归终止条件很明确,只有一个元素时。我们可以分析一下全排列的过程:
首先,我们固定第一个字符a,求后面两个字符bc的排列
当两个字符bc排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面两个字符ac的排列
现在是把c放在第一个位置的时候了,但是记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍是和原先处在第一个位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处于第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列
既然我们已经知道怎么求三个字符的排列,那么固定第一个字符之后求后面两个字符的排列,就是典型的递归思路了。

function Permutation(str)
{
    // write code here
    if(str.length == 0)return '';
    let str_arr = str.split('');
    str_arr.sort();
    let res = [];
    for(let i = 0; i < str_arr.length; i++){
        if(i > 0 && str_arr[i] === str_arr[i-1])continue;
        let front = str_arr.slice(0,i);
        let end = str_arr.slice(i+1);
        PermutationHelp(res,str_arr[i],front.concat(end));
    }
    return res;
     
}
function PermutationHelp(res,temp, arr){
    if (arr.length === 0) {
        res.push(temp);
    } else {
        for(let i = 0; i < arr.length; i++){
            if(i > 0 && arr[i] === arr[i-1])continue;
            let front = arr.slice(0,i);
            let end = arr.slice(i+1);
            PermutationHelp(res,temp+arr[i],front.concat(end));
        }
    }
}

方法二:字典排列算法

/**
     * 2、字典序排列算法
     *
     * 可参考解析: http://www.cnblogs.com/pmars/archive/2013/12/04/3458289.html  (感谢作者)
     *
     * 一个全排列可看做一个字符串,字符串可有前缀、后缀。
     * 生成给定全排列的下一个排列.所谓一个的下一个就是这一个与下一个之间没有其他的。
     * 这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
     *
     * [例]839647521是1--9的排列。1—9的排列最前面的是123456789,最后面的987654321,
     * 从右向左扫描若都是增的,就到了987654321,也就没有下一个了。否则找出第一次出现下降的位置。
     *
     * 【例】 如何得到346987521的下一个
     * 1,从尾部往前找第一个P(i-1) < P(i)的位置
     * 3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
     * 最终找到6是第一个变小的数字,记录下6的位置i-1
     *
     * 2,从i位置往后找到最后一个大于6的数
     * 3 4 6 -> 9 -> 8 -> 7 5 2 1
     * 最终找到7的位置,记录位置为m
     *
     * 3,交换位置i-1和m的值
     * 3 4 7 9 8 6 5 2 1
     * 4,倒序i位置后的所有数据
     * 3 4 7 1 2 5 6 8 9
     * 则347125689为346987521的下一个排列
     *
     * @param str
     * @return
     */

方法三:

function Permutation(str)
{
    // write code here
    //注意按字典序输出
    var result=[];

    if(str.length>0)
    {
        result.push(str);
        var len=str.length;
        var arr=str.split('');
        while(true)
        {
            var a=len-1,b;

            while(arr[a-1]>=arr[a]&&a>=1)
            {
                a--;
            }
            if(a==0){break;}
            b=a;
            while(b<len&&arr[b]>arr[a-1])
            {
                b++;
            }
            var temp;
            temp=arr[a-1];
            arr[a-1]=arr[b-1];
            arr[b-1]=temp;

            var arr1=arr.slice(a);
            arr1.reverse();
            var arr2=arr.slice(0,a);
            arr=arr2.concat(arr1);
            var s=arr.join('');
            result.push(s);
        }
    }
    return result;
}

【题13】用两个栈实现队列

题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

<分析>:

入队:将元素进栈A

出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈;

 如果不为空,栈B直接出栈。

var stackA = []
var stackB = []
function push(node)
{
    stackA.push(node)
}
function pop()
{
    if (stackB.length === 0) {
        if (stackA.length === 0) {
            return null
        } else {
            var len = stackA.length
            for (var i = 0; i < len; i++) {
                stackB.push(stackA.pop())
            }
            return stackB.pop()
        }
    } else {0
        return stackB.pop()
    }
}

拓展:用两个队列实现一个栈的功能

<分析>:

入栈:将元素进队列A

出栈:判断队列A中元素的个数是否为1,如果等于1,则出队列,否则将队列A中的元素   以此出队列并放入队列B,直到队列A中的元素留下一个,然后队列A出队列,再把队列B中的元素出队列以此放入队列A中。

【题】数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

方法一:

function MoreThanHalfNum_Solution(numbers)
{
    var len = numbers.length
    var arrLen = len/2, obj = {}
    for(var i = 0; i < len; i++) {
        if (obj[numbers[i]] === undefined) {
            obj[numbers[i]] = 1
        } else {
            obj[numbers[i]]++
        }
    }
    for (var j = 0; j < len; j++) {
        if (obj[numbers[j]] > arrLen) {
            return numbers[j]
        }
    }
    return 0
}

方法二:关键点:数组中有一个数字出现的次数超过数组长度的一半,那么经过排序之后的数组,超过数组长度一半的数字一定在数组中间,因此判断之后,若存在的话一定是数组中间的数字。

function MoreThanHalfNum_Solution(numbers)
{
    var len = Math.floor(numbers.length/2)
    var count = 0
    var middle = numbers[len]
    numbers.sort((a, b) => {
        return (a-b)
    })
    for (var i = 0; i < numbers.length; i++) {
        if (numbers[i] === middle) {
            count++
        }
    }
    if (count > len) {
        return middle
    } else {
        return 0
    }
}

【题14】连续子数组的最大和:

六大算法之动态规划:https://blog.youkuaiyun.com/zw6161080123/article/details/80639932

漫画:什么是动态规划:http://www.sohu.com/a/153858619_466939

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

function FindGreatestSumOfSubArray(array)
{
    //注意初始值 不能设为0 防止只有负数
    var max = array[0]
    var pre  =array[0]
    if (array.length < 0) {
        return 0
    }
    //从1开始 因为0的情况在初始化时完成了
    for (var i = 1; i < array.length; i++) {
        // 当pre小于0时,就不要在继续往后累加了,因为这样只会越来越小。
        if (pre < 0) pre = 0
        max = Math.max(max, pre + array[i])
        pre = pre + array[i]
    }
    return max
}

【题15】整数中1出现的次数(从1到n整数中1出现的次数)

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

function NumberOf1Between1AndN_Solution(n)
{
    if (n < 1) {
        return 0
    }
    var num = 0, counts = 0
    for (var i = 0; i <= n; i++) {
        num = i
        while (num > 0) {
            if (num%10 === 1) {
                counts++
            }
            num = Math.floor(num/10)
        }
    }
    return counts
}

【题16】把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

function PrintMinNumber(numbers)
{    
    var res = ''
    for (var i = 0; i < numbers.length; i++) {
        for (var j = 0; j < numbers.length - i - 1; j++) {
            var str1 = String(numbers[j]) + String(numbers[j+1])
            var str2 = String(numbers[j+1]) + String(numbers[j])
            if (Number(str1) > Number(str2)) {
                var temp = numbers[j];
                numbers[j] = numbers[j+1];
                numbers[j+1] = temp;
            }
        }
        res = String(numbers[numbers.length - i - 1]) + res
    }
    return res === '' ? '' : Number(res)
}

【题17】第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

function FirstNotRepeatingChar(str)
{
    if (str.length === 0) {
        return -1
    }
    var obj = {}
    for (var i = 0; i < str.length; i++) {
        if (obj[str[i]] === undefined) {
            obj[str[i]] = 1
        } else {
            obj[str[i]]++
        }
    }
    for (var j = 0; j < str.length; j++) {
        if (obj[str[j]] === 1){
            return j
        }
    }
}

【题18】和为S的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

对应每个测试案例,输出两个数,小的先输出。
function FindNumbersWithSum(array, sum)
{
    var resultArray = []
    for (var i = 0; i < array.length; i++) {
        for (var j = 1; j < array.length; j++) {
            if ((array[j] + array[i]) === sum) {
                resultArray.push(array[i])
                resultArray.push(array[j])
                break;
            } 
        }
        if (resultArray.length) {
            break
        }
    }
    var aa = Array.from(new Set(resultArray))
    return aa
}

【题19】和为S的连续正数序列

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

剑指offer课本解析:

function FindContinuousSequence(sum)
{
    var small = 1
    var big = 2
    var middle = (1 + sum)/2
    var cursum = small + big
    var arr = []
    while(small < middle) {
        var aa = []
        if (cursum == sum) {
            for (var i = small; i <= big; i++) {
                aa.push(i)
            }
            arr.push(aa)
        }
        while (cursum < sum && small < middle) {
            big++
            cursum += big
            var aa = []
            if (cursum == sum) {
                for (var i = small; i <= big; i++) {
                    aa.push(i)
                }
                arr.push(aa)
            }
        }
        cursum -=small
        small++
    }
    return arr
}

【题20】扑克牌顺子

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

function IsContinuous(numbers)
{
    var len = numbers.length
    var count = 0 // 记录大王小王即0的个数
    var totalGap = 0
    if (len == 0) {
        return false
    }
    numbers.sort((a, b) => {
        return a-b
    })
    for(var i = 0; i < len; i++) {
        if (numbers[i] === 0) {
            count++
            continue
        }
        if (i < len - 1) {
            var gap = numbers[i+1] - numbers[i] - 1
            if (gap < 0) {
                // 出现值相同的情况
                return false
            } else {
                totalGap += gap
            }
        }
        if (totalGap > count) {
            return false
        }
    }
    return true
}

【题21】正则表达式匹配

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。
 

当模式中的第二个字符不是“*”时:

1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。

2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。

而当模式中的第二个字符是“*”时:

如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:

1、模式后移2字符,相当于x*被忽略;

2、字符串后移1字符,模式后移2字符;

3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;

//s, pattern都是字符串
function match(s, pat) {
    // write code here
     var reg = new RegExp('^'+pattern +'$','g');
    return reg.test(s);
}
//s, pattern都是字符串
function match(s, pat) {
    /** 当pat为空时,若s为空则返回true否则返回false */
    if (pat == "") return s == "";
    /** 当pat长度为1时,直接判断是否匹配s,此时,pat一定不是‘*’  */
    if (pat.length == 1) return s == pat || s.length == 1 && pat == ".";
    /** 当pat长度大于1时,根据pat的第二个字符分情况讨论 */
    if (pat[1] == "*") {
        /** 当pat[1]为"*"时,先尝试直接跳过该任意次数字符 */
        if (!match(s, pat.substr(2))) {
            /** 跳过该字符无法匹配时,依次尝试让s的前1到s.length个字符与该字符匹配 */
            for (let i = 0; i < s.length; i++) {
                if (pat[0] != "." && pat[0] != s[i]) return false;
                if (match(s.substr(i + 1), pat.substr(2))) return true;
            }
            return false;
        } else return true;
    } else {
        /** pat[1] != '*' 则直接尝试匹配当前字符 */
        if (pat[0] != "." && pat[0] != s[0]) return false;
        return match(s.substr(1), pat.substr(1));
    }
}

【题22】表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

//s字符串
function isNumeric(s)
{
    return s.match(/[+-]?\d*(\.\d*)?([eE][+-]?\d+)?/g)[0] === s
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Delicia_Lani

你的鼓励将是我写作的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值