[英]Java - find all combinations of three numbers in sorted array that have a sum smaller than a number
[英]Find the first element in a sorted array that is smaller than the target
在排序數組中,可以使用二進制搜索來執行許多不同種類的操作:
您可以在堆棧溢出中找到#2和#5的答案,它們的答案使用的是二進制搜索的變異,但是沒有固定的算法來回答這些問題,特別是在調整索引時。
例如,在問題3中,找到排序數組中第一個小於或等於目標的元素:給定int[] stocks = new int[]{1, 4, 3, 1, 4, 6};
,我想找到小於5的第一個元素。排序后應該返回4,我的代碼如下:
private static int findMin(int[] arr, int target) {
Arrays.sort(arr);
int lo = 0;
int hi = arr.length - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] > target) {
hi = mid - 1;
} else {
lo = mid;
}
}
return lo;
}
這里的邏輯是:
如果運行它,它實際上會進入無限循環,但是只需將hi = arr.length - 1
的起始索引調整為hi = arr.length;
,實際上效果很好。 我不知道如何真正設置所有條件:如何編寫條件,如何設置hi和lo的起始索引以及使用lo<=hi
或lo < hi
。
有什么幫助嗎?
基本上在上述情況下,您需要的最大元素要小於給定值,即需要找到給定元素的底數。 使用O(logn)中的二進制搜索可以很容易地做到這一點:
您需要考慮的情況如下:
如果最后一個元素小於x,則返回最后一個元素。
如果中點是地板,則返回中點。
請嘗試以下操作:
static int floorInArray(int arr[], int low, int high, int x)
{
if (low > high)
return -1;
// If last element is smaller than x
if (x >= arr[high])
return high;
// Find the middle point
int mid = (low+high)/2;
// If middle point is floor.
if (arr[mid] == x)
return mid;
// If x lies between mid-1 and mid
if (mid > 0 && arr[mid-1] <= x && x < arr[mid])
return mid-1;
// If x is smaller than mid, floor
// must be in left half.
if (x < arr[mid])
return floorInArray(arr, low, mid - 1, x);
// If mid-1 is not floor and x is
// greater than arr[mid],
return floorInArray(arr, mid + 1, high,x);
}
在while循環中, hi == lo
時沒有大小寫
當迭代最后一個元素或數組只有1個元素時,這種情況適用。
將while循環設置為while(lo <= hi)
,它將在搜索所有元素時終止
或在hi
等於lo
時在if循環內設置一個if case。
if(hi == lo)
您可以只使用Arrays.binarySearch(int[] a, int key)
而不是執行自己的二進制搜索,然后相應地調整返回的值。
如果數組中包含搜索鍵的索引,則返回該索引; 否則為(-( 插入點 )-1)。 插入點定義為將鍵插入數組的點:第一個元素的索引大於鍵,如果數組中的所有元素都小於指定的鍵,則為a.length。 請注意,這保證了當且僅當找到鍵時,返回值才> = 0。
您的規則沒有指定在存在多個有效選擇(具有多個相等值的#3或#4或具有等距值的#5)時返回哪個索引,因此下面的代碼中的代碼做出了明確的選擇。 如果您不關心模棱兩可,則可以刪除多余的代碼;如果不同意我的解決方案,則可以更改邏輯。
請注意,當返回值<0時, returnValue = -insertionPoint - 1
insertionPoint = -returnValue - 1
表示insertionPoint = -returnValue - 1
,在代碼中均低於-idx - 1
。 因此,插入點之前的索引是-idx - 2
。
這些方法當然可能返回超出范圍的索引值( -1
或arr.length
),因此調用方始終需要進行檢查。 對於closest()
方法,只有在array為空時才可能發生,在這種情況下它將返回-1
。
public static int smaller(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to before target value(s)
do {
idx--;
} while (idx >= 0 && arr[idx] == target);
return idx;
}
public static int smallerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index prior to insertion point
return -idx - 2;
}
// target found, so skip to last of target value(s)
while (idx < arr.length - 1 && arr[idx + 1] == target) {
idx++;
}
return idx;
}
public static int biggerOrEqual(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
public static int bigger(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx < 0) {
// target not found, so return index of insertion point
return -idx - 1;
}
// target found, so skip to after target value(s)
do {
idx++;
} while (idx < arr.length && arr[idx] == target);
return idx;
}
public static int closest(int[] arr, int target) {
int idx = Arrays.binarySearch(arr, target);
if (idx >= 0) {
// target found, so skip to first of target value(s)
while (idx > 0 && arr[idx - 1] == target) {
idx--;
}
return idx;
}
// target not found, so compare adjacent values
idx = -idx - 1; // insertion point
if (idx == arr.length) // insert after last value
return arr.length - 1; // last value is closest
if (idx == 0) // insert before first value
return 0; // first value is closest
if (target - arr[idx - 1] > arr[idx] - target)
return idx; // higher value is closer
return idx - 1; // lower value is closer, or equal distance
}
測試
public static void main(String... args) {
int[] arr = {1, 4, 3, 1, 4, 6};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println(" | Index | Value |");
System.out.println(" | < <= ~ >= > | < <= ~ >= > |");
System.out.println("--+----------------------+---------------------+");
for (int i = 0; i <= 7; i++)
test(arr, i);
}
public static void test(int[] arr, int target) {
int smaller = smaller (arr, target);
int smallerOrEqual = smallerOrEqual(arr, target);
int closest = closest (arr, target);
int biggerOrEqual = biggerOrEqual (arr, target);
int bigger = bigger (arr, target);
System.out.printf("%d | %3d %3d %3d %3d %3d |%3s %3s %3s %3s %3s | %d%n", target,
smaller, smallerOrEqual, closest, biggerOrEqual, bigger,
(smaller < 0 ? "" : String.valueOf(arr[smaller])),
(smallerOrEqual < 0 ? "" : String.valueOf(arr[smallerOrEqual])),
(closest < 0 ? "" : String.valueOf(arr[closest])),
(biggerOrEqual == arr.length ? "" : String.valueOf(arr[biggerOrEqual])),
(bigger == arr.length ? "" : String.valueOf(arr[bigger])),
target);
}
輸出量
[1, 1, 3, 4, 4, 6]
| Index | Value |
| < <= ~ >= > | < <= ~ >= > |
--+----------------------+---------------------+
0 | -1 -1 0 0 0 | 1 1 1 | 0
1 | -1 1 0 0 2 | 1 1 1 3 | 1
2 | 1 1 1 2 2 | 1 1 1 3 3 | 2
3 | 1 2 2 2 3 | 1 3 3 3 4 | 3
4 | 2 4 3 3 5 | 3 4 4 4 6 | 4
5 | 4 4 4 5 5 | 4 4 4 6 6 | 5
6 | 4 5 5 5 6 | 4 6 6 6 | 6
7 | 5 5 5 6 6 | 6 6 6 | 7
嘗試樹集。 如果您輸入的是數組,請按照以下步驟操作:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.