剑指Offer每日6题(JavaScript版)--第六天

31、剑指offer–整数中1出现的次数(从1到n整数中1出现的次数)

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

思路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为100~199,100的意思为单步出现了100~199,100次,30是因为出现了30次100~199,+(43+1)是因为左后一次301不完整导致。

如果第i位上的数字为0,则第i位可能出现1的次数由其高位决定,若没有高位,则视为0,此时第i位可能出现1的次数为:其高位数*10^(i-1),例如若c为0,则次数为ab*10^2;
如果第i位上的数字为1,则第i位上可能出现1的次数受其高位和低位影响,若没有,则视为0,此时第i位可能出现1的次数:其高位数*10^(i-1)+(低位数+1),例如若c为1,则次数为ab*10^2+(de+1);
如果第i位上的数字大于1,则第i位上可能出现1的次数受其高位影响,若没有,则视为0,此时第i位可能出现1的次数:(其高位数+1)*10^(i-1),例如若c大于1,则次数为(ab+1)*10^2;

思路2:
暴力解决。

代码:

//1、
function NumberOf1Between1AndN_Solution(n)
{
    if(n < 0) return 0;
    var high = n, low, cur, tem, count = 0, i = 1;
    while(high != 0){
        high = parseInt(n / Math.pow(10,i));
        tem = n % Math.pow(10,i);
        cur = parseInt(tem / Math.pow(10,i-1));
        low = tem % Math.pow(10,i - 1);
        if(cur == 1){
            count += high * Math.pow(10,i-1) + low + 1;
        }else if(cur == 0){
            count += high * Math.pow(10,i-1);
        }else{
            count += (high + 1) * Math.pow(10,i-1);
        }
        i++;
    }
    return count;
}
//2、
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++;
            }
            number = Math.floor(number/10);
        }
    }
    return count;
}

32、剑指offer–把数组排成最小的数

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

思路:
排序规则如下:

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

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

代码:

function PrintMinNumber(numbers)
{
    numbers.sort(function(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、剑指offer–丑数

题目描述:
把只包含因子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、剑指offer–第一个只出现一次的字符

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

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

代码:

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、剑指offer–数组中的逆序对

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

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

代码:

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,
        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、剑指offer–两个链表的第一个公共结点

题目描述:
输入两个链表,找出它们的第一个公共结点。

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

代码:

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;
}

剑指Offer每日6题(JavaScript版)-系列文章参考专栏:JavaScript版剑指offer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值