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

浙公网安备 33010602011771号