2.1练习
2.1-1
(1) 31 41 59 26 41
(2) 31 41 59 26 41
(3) 26 31 41 59 41
(4) 26 31 41 41 59
需要注意的是,这里的原数组的后项41在排序后仍在前项41的后面
2.1-2
按降序排序,只需要在循环提内部的if判断中将 < 改为 > 即可,判断每次插入的数字是否比被插入的数组中的元素大,若大,则开始执行
2.1-3
public static int searchNum(int[] arr,int num) {
for(int i = 0;i < arr.length;i++) {
if(arr[i] == num) {
return i;
}
}
return (Integer) null;
}
循环不变式:在循环的每次迭代开始前,A[0...i-1]中不包含值为v的成员
初始化:在第一次循环开始之前,即当赋值i = 0时,数组A[0..-1]中不包含元素,所以显然所查找的数字不在其中,所以循环不变式成立。
保持:假设本次迭代时i = K,那么显然若要执行本次迭代,A[0..k-1]不包含所查找的数字,即循环不变式成立,那么如果可以执行下次迭代,A[k] 必不等于 v,那么A[0..k]中也不包含v,那么循环不变式仍然成立。
终止:当i = arr.length时,循环结束,或在某次循环时A[i] == v终止,当第一种结果出现时,A[0..arr.length - 1]满足循环不变式,即数字不在数组中;当第二种结果出现时,A[0..k-1]满足循环不变式,即数组下标k位置为所查找的数字
2.1-4
public static int[] addBirnaryNum(int[] arrA,int[] arrB) {
int n = arrA.length;
int[] arrC = new int[n+1];
int c = 0;//进位
for(int i = n-1;i >= 0;i--) {
int addBitResult = arrA[i] + arrB[i] + c;
if(addBitResult > 1) { //判断是否有进位出现
c = 1;
}
if(addBitResult == 2 || addBitResult == 0) { //判断当前位的情况
arrC[i+1] = 0;
}else {
arrC[i+1] = 1;
}
}
if(c == 1) {
arrC[0] = 1;
}else {
arrC[0] = 0;
}
return arrC;
}
2.2练习
2.2-1
Θ(n³)
2.2-2
(1)
public static void selectionSort(int[] arr) {
int minmumIndex;
int minmum;
for(int i = 0;i < arr.length - 1;i++) {
minmumIndex = i;
minmum = arr[i];
for(int j = i+1;j < arr.length;j++) {
if(arr[j] < minmum) {
minmumIndex = j;
}
}
int temp = arr[minmumIndex];
arr[minmumIndex] = arr[i];
arr[i] = temp;
}
}
(2)循环不变式是当循环迭代每次开始之前,A[0..k-1]已按序排列
(3)因为在第n-1个元素迭代时,已经比较了第n-1个元素和第n个元素的大小,所以当该次迭代运行完成后,数组已经是排完序了
(4)最好的情况:Θ(n²)
最坏的情况:Θ(n²)
2.2-3
平均需要查找 n/2个元素,最坏需要查找n个元素
平均情况下运行时间:Θ(n)
最坏情况下运行时间:Θ(n)
2.2-4
我们可以首先设计一个针对该问题的一个特定输入,使得这个特定输入是最好的情况,然后不断修改算法,使其针对该特列的运行时间达到最佳
2.3练习
2.3-1
(1)划分成单个元素 3 41 52 26 38 57 9 49
(2)解决两两排序再合并再排序在合并
3,41 26,52 38,57 9,49
3,26,41,52 9,38,49,57
3,9,26,38,41,52,57
2.3-2
public static void combine(int[] arr,int p,int q,int r) {
int n1 = q-p+1;
int n2 = r-q;
int[] arr1 = new int[n1];
int[] arr2 = new int[n2];
for(int i = 0;i < n1;i++) {
arr1[i] = arr[p+i];
}
for(int j = 0;j < n2;j++) {
arr2[j] = arr[q+1+j];
}
int i = 0;
int j = 0;
for(int k = p; k <= r;k++) {
if(arr1[i] <= arr2[j]) {
arr[k] = arr1[i];
i += 1;
if(i == n1) {
for(;j < n2;j++) {
arr[k+1] = arr2[j];
k += 1;
}
break;
}
}else {
arr[k] = arr2[j];
j += 1;
if(j == n2) {
for(;i < n1;i++) {
arr[k+1] = arr1[i];
k += 1;
}
break;
}
}
}
}
2.3-3
证明:
当n = 2时,
T(n)= nlgn = 2*lg2 = 2
∴ 成立
当n = 2^k
假设 T(n/2)= n/2 * lg(n/2) 成立
∵ T(n)= 2T(n/2)+ n
∴ T(n)= n* lg(n/2) + n
= nlgn - n + n
= nlgn
∴ T(n)= nlgn
2.3-4
public static void insert(int[] arr,int p,int q) {
int i;
int key = arr[q];
for(i = q-1;arr[i] >= key;i--) {
arr[i+1] = arr[i];
}
arr[i+1] = key;
}
public static void divideAndConquerInsertionSort(int[] arr,int p,int q) {
if(p < q){
divideAndConquerInsertionSort(arr,p,q-1);
insert(arr,p,q);
}
}
∴ T(n)= T(n-1)+ cn
2.3-5
递归实现
public static int binarySearch(int[] arr,int p,int r,int num) {
if(p <= r) {
int q = (p+r)/2;
if(arr[q] == num) {
return q;
}else if(arr[q] > num) {
return binarySearch(arr,p,q-1,num);
}else {
return binarySearch(arr,q+1,r,num);
}
}
return -1;
}
迭代实现
public static int binarySearch2(int[] arr,int p,int r,int num) {
int q;
while(p <= r) {
q = (p+r)/2;
if(arr[q] == num) {
return q;
}else if(arr[q] > num) {
r= q-1;
}else {
p = q+1;
}
}
return -1;
}
∵ T(n) = T(n/2)
∴ n/2^i = 1
∴ i = lgn
∴ T(n)= c(lgn + 1) = Θ(lgn)
2.3-6
代码实现
public static int binarySearch(int[] arr, int p, int r, int num) {
int mid = 0;
while (p <= r) {
mid = (p + r) / 2;
if (arr[mid] == num) {
break;
} else if (arr[mid] > num) {
r = mid - 1;
} else {
p = mid + 1;
}
}
return mid;
}
public static void insertionSort(int[] arr) {
for(int i = 1;i < arr.length;i++) {
int j = i-1;
int index = binarySearch(arr,0,j,arr[i]);
int temp = arr[i];
if(arr[index] == arr[i]) {
for(;j >= index;j--) {
arr[j+1] = arr[j];
}
}else if(arr[index] > arr[i]) {
for(;j > index - 1;j--) {
arr[j+1] = arr[j];
}
arr[index] = temp;
}else {
for(;j > index;j--) {
arr[j+1] = arr[j];
}
arr[index + 1] = temp;
}
}
}
在该二分查找的方法中,做了修改,如果没有查找到数字,则返回放置时与它最近的一个元素的下标,也就是最后一次mid的位置,如果有这个元素就返回找到元素的下标。
然后在插入排序中进行判断返回的下标在数组中的数字是否与插入元素的值相等,如果相等,则在该元素的后面插入,如果大于插入元素,则在该下标前插入元素,如果小于,则该下标之后插入元素。
但是不难看出,因为需要元素移位,那么循环内部必定嵌套循环,那么最后T(n)= Θ(n²),所以不可能
2.3-7
public static boolean findNumInTwoNumSum(int[] arr,int num) {
int subNum;
int result;
for(int i = 0;i < arr.length - 1;i++) {
subNum = num - arr[i];
result = binarySearch2(arr,0,arr.length - 1,subNum);
if(result != i && result != -1) {
return true;
}
}
return false;
}
思路就是,用所给的数逐个减数组中的元素,然后用二分查找找减后的数,然后存在,即S中存在两数之和刚好为x