剑指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~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; } } |
踏实 踏踏实实~