11天刷剑指offer——JavaScript版——第六天

31、整数中1出现的次数(从1到n整数中1出现的次数)

题目描述

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

思路一

如:30143:

  • 由于3>1,则个位上出现1的次数为(3014+1)*1
  • 由于4>1,则十位上出现1的次数为(301+1)*10
  • 由于1=1,则百位上出现1次数为(30+0)*100+(43+1)
  • 由于0<1,则千位上出现1次数为(3+0)*1000

注:以百位为例,百位出现1为100199,100的意思为单步出现了100199,100次,30是因为出现了30次100~199,+(43+1)是因为左后一次301不完整导致。

  1. 如果第i位上的数字为0,则第i位可能出现1的次数由其高位决定,若没有高位,则视为0,此时第i位可能出现1的次数为:其高位数*10^(i-1),例如若c为0,则次数为ab*10^2;
    2.如果第i位上的数字为1,则第i位上可能出现1的次数受其高位和低位影响,若没有,则视为0,此时第i位可能出现1的次数:其高位数*10^(i-1)+(低位数+1),例如若c为1,则次数为ab*10^2+(de+1);
    3.如果第i位上的数字大于1,则第i位上可能出现1的次数受其高位影响,若没有,则视为0,此时第i位可能出现1的次数:(其高位数+1)*10^(i-1),例如若c大于1,则次数为(ab+1)*10^2;
function NumberOf1Between1AndN_Solution(n)
{
    // write code here
    if(n<0) return 0;
    var high=n,cur,low,tmp,count=0,i=1;
    while(high!=0){
        //parseInt() 函数可解析一个字符串,并返回一个整数。只有字符串中的第一个数字会被返回
        high=parseInt(n/Math.pow(10,i));//获取第i位的高位数(可能好几位)
        tmp=n%Math.pow(10,i);//获取余下数
        cur = parseInt(tmp/Math.pow(10,i-1));//获取第i位
        low=tmp%Math.pow(10,i-1);//低位数
        //判断出现的情况
        if(cur==1){//为1
            count+=high*Math.pow(10,i-1)+low+1;
        }else if(cur==0){//为0
            count+=high*Math.pow(10,i-1);
        }else{
            count+=(high+1)*Math.pow(10,i-1)
        }
        i++
    }
    return count;
}

思路二

暴力解决。

代码

function NumberOf1Between1AndN_Solution(n)
{
    if(n < 0) return 0;
    var count = 0;
    for(var i = 1 ; i <= n ; i++){
        var number = i;
        while(number > 0){
            if(number % 10 == 1){
                count++;
            }
            //Math.floor() 返回小于或等于一个给定数字的最大整数。
            number = Math.floor(number/10);
        }
    }
    return count;
}

32、把数组排成最小的数

题目描述

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

思路

排序规则如下:

若ab > ba 则 a > b,
若ab < ba 则 a < b,
若ab = ba 则 a = b;

然后从小到大拼接即为所求结果

代码

1、sort() 方法用于对数组的元素进行排序。
如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。

2、charAt() 方法可返回指定位置的字符。
字符串中第一个字符的下标是 0。如果参数 index 不在 0 与 string.length 之间,该方法将返回一个空字符串。

function PrintMinNumber(numbers)
{

    numbers.sort(function(a,b){
      //依次比较数组中字符串的大小,搞清楚a,b谁大谁小
        var s1 = a + "" + b;
        var s2 = b + "" + a;
        for(var i = 0 ; i < s1.length ; i++){
            if(s1.charAt(i) > s2.charAt(i)){
                return 1;
            }else if(s1.charAt(i) < s2.charAt(i)){
                return -1;
            }
        }
        return 1;
        //排序好了
    })
    //再按照然后从小到大拼接即为所求结果,这样得到的数是最小的
    var result = "";
    numbers.forEach(function(item){
      //拼接
        result = result.concat(item);
    })
    return result;
}

33、丑数

题目描述

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

思路

下一个丑数是由数组中某个丑数A * 2,B * 3,C * 5中的最小值得来的。

代码

function GetUglyNumber_Solution(index)
{
    // write code here
    if(index == 0) return 0;
    var ugly = [1];
    var factor2 = 0, factor3 = 0, factor5 = 0;
    for(var i = 1 ; i < index ; i++){
        ugly[i] = Math.min(ugly[factor2] * 2 , ugly[factor3] * 3 , ugly[factor5] * 5);
        if(ugly[i] == ugly[factor2] * 2) factor2++;
        if(ugly[i] == ugly[factor3] * 3) factor3++;
        if(ugly[i] == ugly[factor5] * 5) factor5++;
    }
    return ugly[index - 1];
}

34、第一个只出现一次的字符

题目描述

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置

思路

使用map结构,将每次出现字符和出现次数放入map中。

代码

1、map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。
在一个 String 上使用 map 方法获取字符串中每个字符所对应的 ASCII 码组成的数组
一个Map对象在迭代时会根据对象中元素的插入顺序来进行 — 一个 for…of 循环在每次迭代后会返回一个形式为[key,value]的数组。
2、forEach()方法用于调用数组的每个元素,并将元素传递给回调函数。

function FirstNotRepeatingChar(str)
{
    var map = {};
    var strArr = str.split('');
    strArr.forEach(function(item){
        if(!map[item]){
            map[item] = 1;
        }else{
            map[item]++;
        }
    });
    for(var i = 0 ; i < str.length ; i++){
        if(map[str[i]] == 1){
            return i;
        }
    }
    return -1;
}

35、数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5

思路

利用归并排序思想,先求出每个组中逆序对数,然后合并、排序并统计.

代码

(有符号右移)
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。

function InversePairs(data)
{
    if(!data || data.length < 0) return 0;
    var count = 0;
    var copy = data.slice();
    count = mergeSort(data,copy,0,data.length-1);
    return count%1000000007;
}

function mergeSort(data,copy,start,end){
    if(start === end) return 0;
    var mid = (end - start) >> 1, //相当于除以2
        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 count + left + right;
}

36、两个链表的第一个公共结点

题目描述

输入两个链表,找出它们的第一个公共结点。

思路

两个指针,遍历后比较结点的值

代码

function FindFirstCommonNode(pHead1, pHead2)
{
    var p1 = pHead1;
    var p2 = pHead2;
    while(p1 != p2){
        p1 = (p1 == null) ? pHead2 : p1.next;
        p2 = (p2 == null) ? pHead1 : p2.next;
    }
    return p1;
}

猜你喜欢

转载自blog.csdn.net/jiuchabi7492/article/details/88226027