GallopSearch Merge: O (บันทึก (n) * บันทึก (i))มากกว่า O (n)
ฉันไปข้างหน้าและดำเนินการตามคำแนะนำของ greybeard ในความคิดเห็น ส่วนใหญ่เป็นเพราะฉันต้องการรุ่นที่สำคัญภารกิจที่มีประสิทธิภาพสูงของรหัสนี้
- รหัสใช้ gallopSearch ซึ่งเป็น O (log (i)) โดยที่ i คือระยะทางจากดัชนีปัจจุบันซึ่งมีดัชนีที่เกี่ยวข้องอยู่
- รหัสใช้ binarySearch สำหรับหลังจากการค้นหาควบระบุช่วงที่เหมาะสม เนื่องจาก gallop จำกัด สิ่งนี้ให้อยู่ในช่วงที่เล็กลง binarySearch ที่ได้คือ O (log (i))
- ควบม้าและผสานจะดำเนินการไปข้างหลัง สิ่งนี้ไม่ได้ดูเหมือนภารกิจสำคัญ แต่จะช่วยให้สามารถรวมอาร์เรย์ได้ หากหนึ่งในอาร์เรย์ของคุณมีพื้นที่เพียงพอที่จะเก็บค่าผลลัพธ์คุณสามารถใช้มันเป็นอาร์เรย์ผสานและอาร์เรย์ผลลัพธ์ได้ คุณต้องระบุช่วงที่ถูกต้องภายในอาร์เรย์ในกรณีดังกล่าว
- ไม่ต้องการการจัดสรรหน่วยความจำในกรณีนั้น (ประหยัดได้มากในการดำเนินการที่สำคัญ) มันทำให้แน่ใจว่ามันไม่ได้และไม่สามารถเขียนทับค่าที่ไม่ได้ประมวลผลใด ๆ (ซึ่งสามารถทำได้ย้อนหลังเท่านั้น) ในความเป็นจริงคุณใช้อาร์เรย์เดียวกันสำหรับทั้งอินพุตและผลลัพธ์ มันจะไม่มีผลร้ายใด ๆ
- ฉันใช้ Integer.compare () อย่างสม่ำเสมอดังนั้นจึงสามารถเปลี่ยนได้เพื่อวัตถุประสงค์อื่น
- มีโอกาสที่ฉันอาจได้เข้าใจข้อมูลเล็กน้อยและไม่ได้ใช้ประโยชน์ที่ฉันได้พิสูจน์มาแล้ว เช่นการค้นหาไบนารีในช่วงของสองค่าซึ่งหนึ่งค่าถูกตรวจสอบแล้ว อาจมีวิธีที่ดีกว่าในการระบุลูปหลัก, ค่า c การพลิกไม่จำเป็นถ้าพวกมันรวมกันเป็นสองการดำเนินงานตามลำดับ เมื่อคุณรู้ว่าคุณจะทำอย่างอื่นทุกครั้ง มีห้องสำหรับขัดบางอย่าง
นี่ควรเป็นวิธีที่มีประสิทธิภาพที่สุดในการทำสิ่งนี้ด้วยความซับซ้อนของเวลาของO (log (n) * log (i))มากกว่า O (n) และความซับซ้อนของเวลากรณีที่เลวร้ายที่สุดของ O (n) หากอาร์เรย์ของคุณมีลักษณะเป็นก้อนและมีค่าความยาวรวมกันสิ่งนี้จะทำให้คนอื่นแคระอย่างอื่นไม่เช่นนั้นมันจะดีกว่าพวกมัน
มันมีค่าการอ่านสองค่าที่ส่วนท้ายของอาร์เรย์ที่ผสานและค่าการเขียนภายในอาร์เรย์ผลลัพธ์ หลังจากค้นหาว่าค่าใดมีค่าน้อยกว่าจะทำการค้นหาควบเข้าไปในอาร์เรย์นั้น 1, 2, 4, 8, 16, 32, ฯลฯ เมื่อพบช่วงที่ค่าการอ่านของอาร์เรย์อื่นมีค่ามากกว่า มันค้นหาไบนารีในช่วงนั้น (ลดช่วงครึ่ง, ค้นหาครึ่งที่ถูกต้อง, ทำซ้ำจนกระทั่งค่าเดียว) จากนั้นอาร์เรย์จะคัดลอกค่าเหล่านั้นไปยังตำแหน่งเขียน โปรดจำไว้ว่าการย้ายสำเนานั้นจำเป็นที่จะไม่สามารถเขียนทับค่าเดียวกันจากอาร์เรย์การอ่าน (ซึ่งหมายความว่าอาร์เรย์การเขียนและอาร์เรย์การอ่านอาจเป็นค่าเดียวกัน) จากนั้นทำการดำเนินการเดียวกันสำหรับอาเรย์อื่นซึ่งขณะนี้ทราบว่าน้อยกว่าค่าการอ่านใหม่ของอาเรย์อื่น
static public int gallopSearch(int current, int[] array, int v) {
int d = 1;
int seek = current - d;
int prevIteration = seek;
while (seek > 0) {
if (Integer.compare(array[seek], v) <= 0) {
break;
}
prevIteration = seek;
d <<= 1;
seek = current - d;
if (seek < 0) {
seek = 0;
}
}
if (prevIteration != seek) {
seek = binarySearch(array, seek, prevIteration, v);
seek = seek >= 0 ? seek : ~seek;
}
return seek;
}
static public int binarySearch(int[] list, int fromIndex, int toIndex, int v) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = list[mid];
int cmp = Integer.compare(midVal, v);
if (cmp < 0) {
low = mid + 1;
} else if (cmp > 0) {
high = mid - 1;
} else {
return mid;// key found
}
}
return -(low + 1);// key not found.
}
static public int[] sortedArrayMerge(int[] a, int[] b) {
return sortedArrayMerge(null, a, a.length, b, b.length);
}
static public int[] sortedArrayMerge(int[] results, int[] a, int aRead, int b[], int bRead) {
int write = aRead + bRead, length, gallopPos;
if ((results == null) || (results.length < write)) {
results = new int[write];
}
if (aRead > 0 && bRead > 0) {
int c = Integer.compare(a[aRead - 1], b[bRead - 1]);
while (aRead > 0 && bRead > 0) {
switch (c) {
default:
gallopPos = gallopSearch(aRead, a, b[bRead-1]);
length = (aRead - gallopPos);
write -= length;
aRead = gallopPos;
System.arraycopy(a, gallopPos--, results, write, length);
c = -1;
break;
case -1:
gallopPos = gallopSearch(bRead, b, a[aRead-1]);
length = (bRead - gallopPos);
write -= length;
bRead = gallopPos;
System.arraycopy(b, gallopPos--, results, write, length);
c = 1;
break;
}
}
}
if (bRead > 0) {
if (b != results) {
System.arraycopy(b, 0, results, 0, bRead);
}
} else if (aRead > 0) {
if (a != results) {
System.arraycopy(a, 0, results, 0, aRead);
}
}
return results;
}
นี่ควรเป็นวิธีที่มีประสิทธิภาพที่สุดในการทำ
คำตอบบางคำมีความสามารถในการลบซ้ำซ้อน นั่นจะต้องใช้อัลกอริทึม O (n) เพราะคุณต้องเปรียบเทียบแต่ละรายการ ดังนั้นนี่คือแบบสแตนด์อะโลนสำหรับสิ่งนั้นเพื่อนำมาใช้หลังจากความจริง คุณไม่สามารถวิ่งผ่านหลาย ๆ รายการได้หากคุณต้องการดูทั้งหมดแม้ว่าคุณจะสามารถวิ่งผ่านรายการซ้ำได้หากคุณมีจำนวนมาก
static public int removeDuplicates(int[] list, int size) {
int write = 1;
for (int read = 1; read < size; read++) {
if (list[read] == list[read - 1]) {
continue;
}
list[write++] = list[read];
}
return write;
}
อัปเดต: คำตอบก่อนหน้าไม่ใช่รหัสที่น่ากลัว แต่ด้อยกว่าอย่างชัดเจน
การเพิ่มประสิทธิภาพไฮเปอร์ที่ไม่จำเป็นอีกอย่างหนึ่ง ไม่เพียงเรียกใช้ arraycopy สำหรับบิตสุดท้าย แต่ยังรวมถึงการเริ่มต้นด้วย การประมวลผลเบื้องต้นที่ไม่ทับซ้อนใน O (บันทึก (n)) โดย binarySearch เป็นข้อมูล O (log (n) + n) คือ O (n) และในบางกรณีเอฟเฟกต์จะเด่นชัดโดยเฉพาะอย่างยิ่งในกรณีที่ไม่มีการซ้อนทับกันระหว่างอาร์เรย์ที่รวมกัน
private static int binarySearch(int[] array, int low, int high, int v) {
high = high - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = array[mid];
if (midVal > v)
low = mid + 1;
else if (midVal < v)
high = mid - 1;
else
return mid; // key found
}
return low;//traditionally, -(low + 1); // key not found.
}
private static int[] sortedArrayMerge(int a[], int b[]) {
int result[] = new int[a.length + b.length];
int k, i = 0, j = 0;
if (a[0] > b[0]) {
k = i = binarySearch(b, 0, b.length, a[0]);
System.arraycopy(b, 0, result, 0, i);
} else {
k = j = binarySearch(a, 0, a.length, b[0]);
System.arraycopy(a, 0, result, 0, j);
}
while (i < a.length && j < b.length) {
result[k++] = (a[i] < b[j]) ? a[i++] : b[j++];
}
if (j < b.length) {
System.arraycopy(b, j, result, k, (b.length - j));
} else {
System.arraycopy(a, i, result, k, (a.length - i));
}
return result;
}