剑指Offer学习笔记(4)——时间效率

数组中出现次数超过一半的数字
题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

public class Solution {
    /**
     * 采用阵地攻守的思想: 第一个数字作为第一个士兵,守阵地;count = 1;
     * 遇到相同元素,count++; 遇到不相同元素,即为敌人,同归于尽,count--;
     * 当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,
     * 有可能是主元素。 再加一次循环,记录这个士兵的个数看是否大于数组一般即可。
     * @param array
     * @return
     */
    public int MoreThanHalfNum_Solution(int[] array) {
        int length = array.length;
        if (array == null || length <= 0) {
            return 0;
        }
 
        int result = array[0];
        int times = 1;
        for (int i = 1; i < length; i++) {
            if (times == 0) {
                result = array[i];
                times = 1;
            else {
                if (array[i] == result) {
                    times++;
                else {
                    times--;
                }
            }
        }
 
         
        times = 0;
        for (int i = 0; i < length; i++) {
            if (result == array[i]) {
                times++;
            }
        }
 
        if (times * 2 < length) {
            result = 0;
        }
        return result;
    }
}

最小的K个数
题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
import java.util.ArrayList;
public class Solution {
    /**
     * 最小的K个数
     * @param input
     * @param k
     * @return
     */
    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
        ArrayList<Integer> aList = new ArrayList<Integer>();
        if (input.length < k || input == null) {
            return aList;
        }
        if (k == 0) {
            return aList;
        }
        int len = input.length;
        findSort(input, 0, len - 1, k);
        for(int i=0;i<k;i++){
            aList.add(input[i]);
        }
        return aList;
    }
 
    /*
    递归查找
    */
    private void findSort(int[] input, int p, int r, int k) {
        if (p == r) {
            return;
        }
        int q = partition(input, p, r);
        int temp = q - p + 1;///当前的长度
         
        if (temp == k) {
            return;
        } else if (k < temp) {
            findSort(input, p, q - 1, k);
        } else {
            findSort(input, q + 1, r, k - temp);
        }
 
    }
   /*
    分治法来实现最小k的查找/*
    */
    private int partition(int[] input, int p, int q) {
        int x = input[q];
        int i = p - 1;
        for (int j = p; j < q ; j++) {
            if (input[j] <= x) {
                i = i + 1;
                int temp = input[i];
                input[i] = input[j];
                input[j] = temp;
            }
        }
 
        input[q] = input[i + 1];
        input[i + 1] = x;
        return i + 1;
    }
}
连续子数组的最大和
题目描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class Solution {
    /*
    分治法求解最大字数组 这个算法自己曾经实现过 不过有些问题没有解决
     
    */
     
   public int FindGreatestSumOfSubArray(int[] array) {
        if (array.length == 0 || array == null) {
            return 0;
        }
         
        int result = findMaxSubArray(array, 0, array.length - 1);
        return result;
    }
 
    private int findMaxSubArray(int[] arr, int left, int right) {
        int result=0;
        if (left == right) {
            result=arr[left];
            return result;
        else {
            int mid = (left + right) / 2;
            int saleft = findMaxSubArray(arr, left, mid);
            int saright = findMaxSubArray(arr, mid+1, right);
 
            int sacross = findCrossingMaxSubArray(arr, left, mid,
                    right);
 
            if (saleft > saright
                    && saleft > sacross) {
                return saleft;
            else if (saright > saleft
                    && saright > sacross) {
                return saright;
            else {
                return sacross;
            }
        }
    }
 
    private int findCrossingMaxSubArray(int[] arr, int left, int mid, int right) {
        int sum=0;
        int begin=0;
        int end=0;
 
        int leftsum = arr[mid] ;
        sum=arr[mid];
        for(int i=mid-1;i>=left;i--){
            sum=sum+arr[i];
            if(sum>leftsum){
                leftsum=sum;
                begin=i;
            }
        }
        int rightsum = arr[mid+1];
        sum=arr[mid+1];
        for(int i=mid+2;i<=right;i++){
            sum=sum+arr[i];
            if(sum>rightsum){
                rightsum=sum;
                end=i;
            }
        }
        return leftsum+rightsum;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Solution {
    public static int FindGreatestSumOfSubArray(int[] array) {
        if(array.length==0return 0;
        int sum = 0 ,result = array[0];
        for (int i = 0; i < array.length; i++) {
            if(sum<0)
                sum = array[i];
            else
                sum += array[i];
            result = Math.max(result, sum);
        }
        return result;
    }
}
整数中1出现的次数(从1到n整数中1出现的次数)
题目描述:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
 
        if(n<=0){
            return 0;
        }
        String str = Integer.toString(n);
        char[] strN=str.toCharArray();
         
        return NumberOf1(strN,0);
         
 
    }
 
    private int NumberOf1(char[] strN,int loc) {
        if(strN==null||strN[loc]<'0'||strN[loc]>'9'||strN[loc]=='\0'){
            return 0;
        }
         
        int first=strN[loc]-'0';
        //剩余长度
        int len = strN.length-loc;//剩余 长度 下标是从0开始
         
        if(len==1&&first==0){
            return 0;
        }
        if(len==1&&first>0){
            return 1;
        }
         
        int numFirstDigit=0;
        if(first>1){
            numFirstDigit=PowerBase10(len-1);
        }else if(first==1){
            numFirstDigit=Atoi(strN,loc+1)+1;//将后序的字符转换成为数值
        }
        //除了开头第一位的所有其他的四位数中的情况
        int numOtherDigit=first*(len-1)*PowerBase10(len-2);
         
        int numRecursive = NumberOf1(strN, loc+1);
         
        return numFirstDigit+numOtherDigit+numRecursive;
         
    }
 
    private int Atoi(char[] strN, int loc) {
        int num = 0;
        for(int i=loc;i<strN.length;i++){
            num=num*10+(strN[i]-'0');
        }
        return num;
    }
 
    private int PowerBase10(int n) {
         
        int res=1;
        for(int i=0;i<n;i++){
            res*=10;
        }
        return res;
    }
}
把数组排成最小的数
题目描述:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.util.ArrayList;
 
public class Solution {
   /**
     * 生成最小数值的数组排列 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
     * 例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
     *
     * @param numbers
     * @return
     *
     *         这个题目主要是想找到一个排序规则,数组根据这个排序规则来排成一个最小的数字。要确定排序规则就要比较两个数字,也就是比较
     *         m和n,我们需要一个规则判断m和n哪一个应该排在前面,而不是仅仅比较两个数字的值哪个更大。
     *
     *         根据题目要求,两个数字m和n 拼接成为mn和nm如果mn小于nm,那么我们应该打印出mn,也就是m应该排在n 的前面。
     *         我们定义此时m<n.这是我们自定义的大小比较关系。
     *
     *         拼接称为字符串,按照字符串比较大小就可以了。
     */
    public String PrintMinNumber(int[] numbers) {
 
        if (numbers.length == 0 || numbers == null) {
            return "";
        }
 
        int len = numbers.length;
        String[] strNums = new String[len];
        for (int i = 0; i < len; i++) {
            strNums[i] = Integer.toString(numbers[i]);
            // construct string from a int array
        }
 
        String res = qSortStrArray(strNums, len);
 
        return res;
    }
 
    private String qSortStrArray(String[] strNums, int len) {
        if (strNums == null || strNums.length == 0)
            return null;
         
        for(int i=0;i<len-1;i++){
            for(int j=i;j<len;j++){
                if((strNums[i]+strNums[j]).compareTo(strNums[j]+strNums[i])>0){
                    String temp = strNums[i];
                    strNums[i]=strNums[j];
                    strNums[j]=temp;
                }
            }
        }
         
        String res="";
        for(int i=0;i<len;i++){
            res+=strNums[i];
        }
        return res;
 
    }
}
posted @ 2016-04-02 22:23  snowwolf101  阅读(223)  评论(0编辑  收藏  举报