给定一个排好序的数组,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)。
希望得到更好的实现,和对复杂度的分析。