《剑指offer》算法题第九天
今日题目:
- 整数中1出现的次数
- 把数组排成最小的数
- 丑数
- 第一个只出现一次的字符位置
今天的题目相对比较难,特别是第1题和第3题很考验数学功底,下面我们一题一题来看看。
1.整数中1出现的次数
题目描述: 输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数。例如,输入12,1~12这些整数中包含1的数字有1,10,11,和12,1一共出现了5次。
思路:
这道题分别有递归和迭代两种解法,第一次看见这个题目比较难想到,可参考:
递归:http://blog.csdn.net/gatieme/article/details/51292339
代码如下:
1 //递归 2 public class Solution { 3 public int NumberOf1Between1AndN_Solution(int n) { 4 if(n == 0) return 0; 5 else if(n > 0 && n < 10) return 1; 6 else{ 7 int high = n; 8 int weight = 1; 9 while(high >= 10){ 10 high /= 10; 11 weight *= 10; 12 } 13 14 if(high == 1){ 15 return NumberOf1Between1AndN_Solution(weight-1)+ 16 NumberOf1Between1AndN_Solution(n-weight)+ 17 (n - weight + 1); 18 }else{ 19 return high*NumberOf1Between1AndN_Solution(weight-1)+ 20 NumberOf1Between1AndN_Solution(n - high*weight)+ 21 weight; 22 } 23 24 } 25 } 26 } 27 28 29 //迭代 30 public class Solution { 31 int NumberOf1Between1AndN_Solution(int n){ 32 int ones = 0; 33 for (int m = 1; m <= n; m *= 10) { 34 int a = n/m, b = n%m; 35 if(a%10 == 0) 36 ones += a / 10 * m; 37 else if(a%10 == 1) 38 ones += (a/10*m) + (b+1); 39 else 40 ones += (a/10+1)* m; 41 } 42 return ones; 43 } 44 }
2.把数组排成最小的数
题目描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:
重新定义一种比较方法,然后对数组进行排序,最后再输出,博主这边是维护了一个最小堆。
代码如下:
1 public class Solution { 2 public String PrintMinNumber(int [] numbers) { 3 PriorityQueue<String> minHeap = new PriorityQueue(new Comparator<String>(){ 4 public int compare(String str1,String str2){ 5 String str_12 = str1+str2; 6 String str_21 = str2+str1; 7 return str_12.compareTo(str_21); 8 } 9 }); 10 for(int n:numbers){ 11 minHeap.add(""+n); 12 } 13 StringBuffer sb = new StringBuffer(); 14 while(!minHeap.isEmpty()){ 15 sb.append(minHeap.poll()); 16 } 17 return sb.toString(); 18 } 19 }
3. 丑数
题目描述:
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:
由丑数的定义,每个丑数都是可以由比他小的丑数乘以2,3,或者5得到的,所以这边维护了一个数组和三个分别指向下一步将乘以2,3,或者5的数的指针,这样方便来求解下一个丑数,减小时间复杂度。
代码如下:
1 public class Solution { 2 public int GetUglyNumber_Solution(int index) { 3 if(index <= 0) return 0; 4 int[] ugly_nums = new int[index]; 5 ugly_nums[0] = 1; 6 int next = 1; 7 8 int p2 = 0,p3 = 0,p5 = 0; 9 while(next < index){ 10 //找到下一个丑数 11 int min = Min(ugly_nums[p2]*2, 12 ugly_nums[p3]*3,ugly_nums[p5]*5); 13 ugly_nums[next] = min; 14 //移动指针,将它们指向下一个该乘的数 15 while(ugly_nums[p2]*2 <= ugly_nums[next]) 16 p2++; 17 while(ugly_nums[p3]*3 <= ugly_nums[next]) 18 p3++; 19 while(ugly_nums[p5]*5 <= ugly_nums[next]) 20 p5++; 21 22 next++; 23 } 24 return ugly_nums[next-1]; 25 } 26 27 public int Min(int num1,int num2,int num3){ 28 int min = (num1 > num2)?num2:num1; 29 return min<num3?min:num3; 30 } 31 }
4.第一个只出现一次的字符位置
题目描述: 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置。
思路:
比较简单,维护一个hashmap,将字符和出现的次数放入表中。
代码如下:
1 import java.util.*; 2 public class Solution { 3 public int FirstNotRepeatingChar(String str) { 4 if(str.length() <= 0) return -1; 5 HashMap<Character,Integer> map = new HashMap(); 6 for(int i = 0; i < str.length(); i++){ 7 char c = str.charAt(i); 8 if(!map.containsKey(c)){ 9 map.put(c,1); 10 }else{ 11 int val = map.get(c); 12 map.put(c,val+1); 13 } 14 } 15 for(int i = 0; i < str.length(); i++){ 16 if(map.get(str.charAt(i)) == 1) 17 return i; 18 } 19 return -1; 20 21 } 22 }