剑指offer29-32

第29题
题目描述:
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

题目分析:
本题可以直接计算每个相邻子集的大小,然后将最大的相邻子集返回即可。
代码如下:

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        //得到数组的长度
        int len = array.length;
        if(len == 1){
            return array[0];
        }
        int sum = 0;
        int max = array[0];
        for(int i=0;i<len;i++){
            for(int j = i;j<len;j++){
                sum +=array[j];
                if(sum>max){
                    max = sum;
                }
            }
            sum = 0;
        }
        return max;
    }
}

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

题目分析:
同样本题可以使用遍历的方式,将每个数中包含1的个数统计出来,然后进行累计出1其中包含1的个数。

代码如下:

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        
        if(n<0){
            return 0;
        }
        int count=0;
        for(int i=1;i<=n;i++){
            count += numberOf1(i);
        }
        return count;
    }
    //每个数中1的个数
    public static int numberOf1(int n){
        int count = 0;
        while(n>0){
            if(n%10 == 1){
                count++;
            }
            n = n/10;
        }
        return count;
    }
}

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

题目分析:
这道题目其实是希望我们能够找到一个排序规则,数组根据这个规则排序之后能排成一个最小的数字。要确定排序规则,就要比较两个数字,也就是给出两个数字m和n,我们需要确定一个规则判断m和n哪个应该排在前面,而不是仅仅比较这两个数字的值哪个更大。

确立规则:
根据题目的要求,两个数字m和n能拼成数字mn和nm。如果mn<nm,那么我们应该打印出mn,即m应该排在n的前面,我们此时定义m小于n;反之,如果nm<mn,我们定义n小于m。如果mn=nm,我们定义m等于n。(注:符号的<,>, =是常规意义的数值大小,而文字的“大于”,“小于”,“等于”表示我们新定义的大小关系)。

因存在大数问题,故我们把数字转化为字符串,另外把数字m和数字n拼接起来得到mn和nm,它们的位数肯定是相同的,因此比较它们的大小只需要按照字符串大小的比较规则就可以了。

下面给出字符串的CompareTo方法:
在这里插入图片描述代码如下:

import java.util.*;

public class Solution {
    public String PrintMinNumber(int [] numbers) {
        
        if(numbers == null && numbers.length == 0){
            return "";
        }
        
        //转为字符串数组
        String[] arr = new String[numbers.length];
        for(int i=0;i<numbers.length;i++){
            //将数组中的整型并取出转为字符串存在arr中
            arr[i] = String.valueOf(numbers[i]);
        }
        
        Arrays.sort(arr,new Comparator<String>(){
            public int compare(String a,String b){
                String str1 = a+b;
                String str2 = b+a;
                
                return str1.compareTo(str2);
            }
        });
        
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<arr.length;i++){
            sb.append(arr[i]);
        }
        return sb.toString();
    }
}

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

问题分析:

首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,那么我们从1开始乘以2,3,5,就得到2,3,5三个丑数,在从这三个丑数出发乘以2,3,5就得到4,6,10,6,9,15,10,15,25九个丑数,我们发现这种方***得到重复的丑数,而且我们题目要求第N个丑数,这样的方法得到的丑数也是无序的。那么我们可以维护三个队列:
(1)丑数数组: 1
乘以2的队列:2
乘以3的队列:3
乘以5的队列:5
选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(2)丑数数组:1,2
乘以2的队列:4
乘以3的队列:3,6
乘以5的队列:5,10
选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(3)丑数数组:1,2,3
乘以2的队列:4,6
乘以3的队列:6,9
乘以5的队列:5,10,15
选择三个队列头里最小的数4加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(4)丑数数组:1,2,3,4
乘以2的队列:6,8
乘以3的队列:6,9,12
乘以5的队列:5,10,15,20
选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(5)丑数数组:1,2,3,4,5
乘以2的队列:6,8,10,
乘以3的队列:6,9,12,15
乘以5的队列:10,15,20,25
选择三个队列头里最小的数6加入丑数数组,但我们发现,有两个队列头都为6,所以我们弹出两个队列头,同时将12,18,30放入三个队列;
……………………
疑问:
1.为什么分三个队列?
丑数数组里的数一定是有序的,因为我们是从丑数数组里的数乘以2,3,5选出的最小数,一定比以前未乘以2,3,5大,同时对于三个队列内部,按先后顺序乘以2,3,5分别放入,所以同一个队列内部也是有序的;
2.为什么比较三个队列头部最小的数放入丑数数组?
因为三个队列是有序的,所以取出三个头中最小的,等同于找到了三个队列所有数中最小的。
实现思路:
我们没有必要维护三个队列,只需要记录三个指针显示到达哪一步;“|”表示指针,arr表示丑数数组;
(1)1
|2
|3
|5
目前指针指向0,0,0,队列头arr[0] * 2 = 2, arr[0] * 3 = 3, arr[0] * 5 = 5
(2)1 2
2 |4
|3 6
|5 10
目前指针指向1,0,0,队列头arr[1] * 2 = 4, arr[0] * 3 = 3, arr[0] * 5 = 5
(3)1 2 3
2| 4 6
3 |6 9
|5 10 15
目前指针指向1,1,0,队列头arr[1] * 2 = 4, arr[1] * 3 = 6, arr[0] * 5 = 5
………………

代码如下:

import java.util.*;
public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index <= 0){
            return 0;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        //add进第一个丑数1
        list.add(1);
        int i2=0;
        int i3=0;
        int i5=0;
        while(list.size()<index){
            //取出三个数
            int num1 = list.get(i2)*2;
            int num2 = list.get(i3)*3;
            int num3 = list.get(i5)*5;
            int min = Math.min(num1,Math.min(num2,num3));
            list.add(min);
            
            //对应下标往后移动
            if(min == num1){
                i2++;
            }
            if(min == num2){
                i3++;
            }
            if(min == num3){
                i5++;
            }
        }
        return list.get(index-1);
    }
}
原创文章 16 获赞 11 访问量 344

猜你喜欢

转载自blog.csdn.net/qq_38041105/article/details/105757040