给定一个排好序的数组,A[1],A[2],...A[n],起元素数值两两不等,设计一个高效算法找出中间所有A[i]=i的下标,并分析其复杂度(必须分析复杂度)。
package com.patrick.bishi;
import java.util.HashSet;
import java.util.Set;
/**
* @date 22/09 2013
* @author patrick
*
*/
public class FindMatch {
private int a[];
private float b[];
private static Set<Integer> set = new HashSet<Integer>();
public int[] getA() {
return a;
}
public void setA(int[] a) {
this.a = a;
}
public float[] getB() {
return b;
}
public void setB(float[] b) {
this.b = b;
}
public FindMatch(float a[]) {
this.b = a;
}
public FindMatch(int a[]) {
this.a = a;
}
public FindMatch() {
}
public static void main(String[] args) {
int a[] = { -4, -3, -1, 0, 2, 3, 6, 7, 8, 9, 11, 12, 14, 15, 17 };
float b[] = { 1.1f, 1.2f, 1.3f, 2.0f, 4, 5, 6, 6.1f, 8.0f };
FindMatch fm = new FindMatch();
fm.setA(a);
fm.setB(b);
fm.testB();
}
public void testA() {
for (int i = 0; i < a.length; i++) {
System.out.println("A[" + i + "] = " + a[i]);
}
int minPos = 0;
int maxPos = a.length - 1;
find(minPos, maxPos);
int count = set.size();
System.out.println("A[i]=i count=" + count);
for (int pos : set) {
System.out.print(pos + ", ");
}
}
public void testB() {
for (int i = 0; i < b.length; i++) {
System.out.println("B[" + i + "] = " + b[i]);
}
int minPos = 0;
int maxPos = b.length - 1;
findF(minPos, maxPos);
int count = set.size();
System.out.println("B[i]=i count=" + count);
for (int pos : set) {
System.out.print(pos + ", ");
}
}
private void find(int minPos, int maxPos) {
int midVal, minVal, maxVal, d, p;
if (maxPos < minPos) {
return;
}
minVal = a[minPos];
maxVal = a[maxPos];
if (minVal > maxPos || maxVal < minPos) {
return;
}
int midPos = minPos + (maxPos - minPos) / 2;
midVal = a[midPos];
if (midVal == midPos) {
System.out.println("add one:" + midPos);
set.add(midPos);
}
if (midVal <= 0) {
minPos = midPos + 1;
find(minPos, maxPos);
} else if (midVal >= maxPos) {
maxPos = midPos - 1;
find(minPos, maxPos);
} else {
// 整形可以进一步优化
if (midVal < midPos) {
d = midPos / midVal;
if (d != 1) {
p = midVal * (d - 1);
find(minPos, midPos - p - 1);
find(midPos + 1, maxPos);
return;
}
} else {
d = midVal / midPos;
if (d != 1) {
p = midPos * (d - 1);
find(minPos, midPos);
find(midPos + p + 1, maxPos);
return;
}
}
find(minPos, midPos - 1);
find(midPos + 1, maxPos);
}
}
private void findF(int minPos, int maxPos) {
float midVal, minVal, maxVal;
int d, p;
if (maxPos < minPos) {
return;
}
minVal = b[minPos];
maxVal = b[maxPos];
if (minVal > maxPos || maxVal < minPos) {
return;
}
int midPos = minPos + (maxPos - minPos) / 2;
midVal = b[midPos];
if (midVal == midPos) {
System.out.println("add one:" + midPos);
set.add(midPos);
}
if (midVal <= 0) {
minPos = midPos + 1;
find(minPos, maxPos);
} else if (midVal >= maxPos) {
maxPos = midPos - 1;
find(minPos, maxPos);
} else {
if (midVal < midPos) {
d = (int) (midPos / midVal);
if (d != 1) {
p = (int) (midVal * (d - 1));
findF(minPos, midPos - p - 1);
findF(midPos + 1, maxPos);
return;
}
} else {
d = (int) (midVal / midPos);
if (d != 1) {
p = midPos * (d - 1);
findF(minPos, midPos);
findF(midPos + p + 1, maxPos);
return;
}
}
findF(minPos, midPos - 1);
findF(midPos + 1, maxPos);
}
}
}
复杂度:
空间复杂度:不考虑用Set保存下标,中间过程中用到了8个变量,分别保存最大、中间、最小位置和它们各自的值,还有两个缩小范围的计算变量。
时间复杂度:用到了递归,二分法,因为本身最差的时间复杂度就是O(n),在本实现下平均复杂度应该小于O(n/2)。
希望得到更好的实现,和对复杂度的分析。