1、整数中1出现的次数
题目描述:
求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路:
直接转成char[ ]统计
代码:
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int count = 0;
for(int i=1;i<=n;i++){
char[] str = (""+i).toCharArray();
for(int j=0;j<str.length;j++){
if(str[j]=='1'){
count++;
}
}
}
return count;
}
}
2、把数组排成最小的数字
题目描述:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:
也就是说,把数组按照最高位最小的在前的序列排序。这个排序和String的排序相似,故先转为String再进行排序。
出错点:
1、考虑33,34,332,的情况,如果直接使用String的compareTo,顺序为33,332,34,但是实际上是332,33,34。所以如果第一位相同时,重写比较代码,当遇到332这个数字时,找到多出的那一位比较与第一个数字的大小,如果较小要排在前面(2<3)。
2、考虑1,11,111,在使用while寻找多出的那一位时(上述的2),如果全都和第一位相同,不要越界访问。
代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Solution {
public String PrintMinNumber(int [] numbers) {
ArrayList<String> num = new ArrayList<>();
for(int i=0;i<numbers.length;i++){
num.add(numbers[i]+"");
}
Collections.sort(num,new Comparator<String>(){
public int compare(String s1,String s2){
if(s1.charAt(0)!=s2.charAt(0)||s1.length()==s2.length()){
return s1.compareTo(s2);
}else{
if(s1.compareTo(s2)<0){
//s1 len < s2 len
return cmp(s1,s2);
}else{
return -cmp(s2,s1);
}
}
}
});
String result = "";
for(int i=0;i<num.size();i++){
result+=num.get(i);
}
return result;
}
public static int cmp(String s1,String s2){
char first = s1.charAt(0);
for(int i=1;i<s1.length();i++){
if(s1.charAt(i)>s2.charAt(i)){
return 1;
}else if(s1.charAt(i)<s2.charAt(i)){
return -1;
}else{
continue;
}
}
int index = s1.length();
while(index<s2.length()&&first==s2.charAt(index)){
index++;
}
if(index==s2.length()){
return 0;
}
if(first>s2.charAt(index)){
return 1;
}else{
return -1;
}
}
}
3、丑数
题目描述:
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路:
如果直接按1,2,3,……判断会超时。那么我们只要从1,2,3,5逐步乘以2,3,5,按从小到大即可。
现在问题的关键就是,如何从小到大。一个数A可以乘以2,3,5,但是不一定比(A+1)* 2都小。
因此我们需要三个指针(*2,*3,*5),指向当前丑数,找出最小的下一位数,则将该指针指向下一位丑数(A+1),而其他指针仍然指向A。
代码:
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index<=0){
return 0;
}
int[] uglys = new int[index];
uglys[0] = 1;
int pointer2 = 0;
int pointer3 = 0;
int pointer5 = 0;
for(int i = 1; i< index;i++){
int next = Math.min(uglys[pointer2]*2,
Math.min(uglys[pointer3]*3,uglys[pointer5]*5));
if(next==uglys[pointer2]*2)pointer2++;
if(next==uglys[pointer3]*3)pointer3++;
if(next==uglys[pointer5]*5)pointer5++;
uglys[i] = next;
}
return uglys[index-1];
}
}
4、第一个只出现一次的字符
题目描述:
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
思路:
循环一次,记录每个字符的次数,然后找出出现为1的第一个字符。
代码:
import java.util.ArrayList;
public class Solution {
public int FirstNotRepeatingChar(String str) {
if(str==null||str.length()==0){
return -1;
}
ArrayList<Character> characters = new ArrayList<>();
ArrayList<Integer> counts = new ArrayList<>();
ArrayList<Integer> indexs = new ArrayList<>();
for(int i=0;i<str.length();i++){
Character c = str.charAt(i);
int index = characters.indexOf(c);
if(index>=0){
int count = counts.get(index)+1;
counts.remove(index);
counts.add(index,count);
}else{
characters.add(c);
counts.add(new Integer(1));
indexs.add(i);
}
}
int i = counts.indexOf(new Integer(1));
if(i<0){
return -1;
}else{
return indexs.get(i);
}
}
}
5、数组中的逆序对
题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
示例:1,2,3,4,5,6,7,0
输出:7
思路:
实质就是排序,将每一个数按位移动后排成从小到大的顺序所需的移动次数即题解。
不管时间复杂度的话,及使用冒泡排序,依次比较,就可以得出结果。
但是题目有时间限制,采用归并排序。
归并排序的核心是计算移动次数counter += (mid-i+1)
注意点:
数字太大要用long,然后结果转int
代码:
public class Solution {
long counter = 0;
public int InversePairs(int [] array) {
if(array==null||array.length==0){
return -1;
}
mergeSort(array);
return (int)(counter%1000000007);
}
public void mergeSort(int[] array){
sort(array,0,array.length-1);
}
public void sort(int[] array,int left,int right){
if(left<right){
int mid = (left+right)/2;
sort(array,left,mid);
sort(array,mid+1,right);
merge(array,left,mid,right);
}
}
public void merge(int[] array, int left,int mid, int right){
int[] temp = new int[right-left+1];
int i = left, j = mid + 1, k = 0;
while(i<=mid&&j<=right){
if(array[i]<=array[j]){
temp[k++] = array[i++];
}else{
temp[k++] = array[j++];
counter += mid - i + 1;//core
}
}
while(i<=mid){
temp[k++] = array[i++];
}
while(j<=right){
temp[k++] = array[j++];
}
for(int p=0;p<temp.length;p++){
array[left+p] = temp[p];
}
}
}