您的位置:首页 > 职场人生

剑指Offer:面试题32——从1到n整数中1出现的次数(java实现)

2016-07-08 17:10 696 查看
问题描述:

输入一个整数n,求1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1的数字有1,10,11,12,1一共出现了5次。

思路:(不考虑时间效率的解法,肯定不是面试官期望的)

直观想法:累加1到n中每个整数中1出现的次数。

每个整数中1出现的次数可以由除以10和模10来计算得到。

代码如下:

boolean invalidInput = false;

//不考虑时间效率的解法
public int NumberOf1Between1AndN_Solution(int n) {

if(n <= 0){
invalidInput = true;
return 0;
}

int number = 0;
for(int i = 1; i <= n; i++){
number += NumberOf1(i);
}

return number;
}

public int NumberOf1(int n){
int number = 0;

while(n > 0){
if(n % 10 == 1){
number++;

}

n = n/10;
}

return number;
}


思路2:从数字规律着手明显提高时间效率的解法,能让面试官耳目一新

首先将1-n根据最高为分成两段,比如1-21345,分为1-1345与1346-21345

从最高位开始,每次分析最高位出现1的次数(用字符串)。然后剥去最高位进行递归求解。

代码:

public class Solution {
boolean invalidInput = false;

//时间复杂度为O(logn)
public int NumberOf1Between1AndN_Solution(int n) {

if(n <= 0){
invalidInput = true;
return 0;
}

StringBuilder s = new StringBuilder(((Integer)n).toString());

return NumberOf1(s);

}

int NumberOf1(StringBuilder s){
if(s == null || s.length() == 0 || s.charAt(0) < '0' || s.charAt(s.length()- 1) > '9'){
return 0;
}

int first = s.charAt(0) - '0';

int length = s.length();

if(length == 1 && first == 0){
return 0;
}

if(length == 1 && first > 0){
return 1;
}

//假设n = 21345
//numFirstDigit是数字10000 - 19999 的第一个位中的数目
int numFirstDigit = 0;
if(first > 1){
numFirstDigit = PowerBase10(length - 1);

}else if(first == 1){
numFirstDigit = Integer.parseInt(s.substring(1)) + 1;

}
//numOtherDigits是1346 - 21345除了第一位之外的数位中的数目
int numOtherDigits = first * (length - 1) * PowerBase10(length - 2);
//numRecursive是1 - 1345中的数目
int numRecursive = NumberOf1(s.deleteCharAt(0));

return numFirstDigit + numOtherDigits + numRecursive;
}

int PowerBase10(int n){
int result = 1;
for(int i = 0; i < n; i++){
result *= 10;

}

return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: