剑指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== 0 return  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;
 
     }
}

转载于:https://www.cnblogs.com/mrzhang123/p/5365798.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值