N-Base 改进的二分搜索算法
N-Base modified Binary Search是一种基于数基的算法,可用于在排序数组 arr[] 中查找元素。该算法是按位二分查找的扩展,运行时间相似。
例子:
Input: arr[] = {0, 1, 4, 5, 8, 11, 15, 21, 45, 70, 100}, target = 45
Output: 7
Explanation: The value 45 is present at index 7
Input: arr[] = {1, 6, 8, 10}, target = 9
Output: -1
Explanation: The value 9 is not present in the given array.
直觉:一个数系的所有数字都可以用另一个数系来表示,该数系以任何数(例如2、3、7)为基础。例如,十进制数字系统的 7在以 3为底的数字系统中可以表示为(21 ) 3 。因此,可以使用任何数N作为数系的基数来实现按位二进制搜索的概念。
方法:通过将基数(从 2 开始的任何正整数)的幂加到总和(最初为 0)来搜索目标元素的索引。当找到这样的幂时,计算可以用于找到目标索引的次数,并将该值与总和相加。计算一个幂可以使用多少次的部分类似于二分查找文章中的“按位二分查找”。
- 定义一个基数,以及大于或等于基数的 2 的幂(2 的幂将有助于计算可以有效地将基数添加到最终索引的次数)
- 计算大于数组大小的基数 (N)的第一次幂。 ( N k其中 k 是大于或等于 1 的整数,X k是大于或等于数组大小的基数的第一次幂)。
- 将索引(finId)初始化为 0,它将存储目标元素应该在所有迭代结束时的最终位置。
- 在计算的功率大于 0 时循环,并且每次将其除以基值。
- 检查此电源可以使用多少次并将该值添加到 finId。
- 要检查这一点,请使用下面提到的条件:
- finId + power of base < array size(M)
- value at finId + power of base ≤ target
迭代完成时检查最终索引处的值是否与目标相同。如果不是,则该值不存在于数组中。
插图:请参阅下图以更好地理解。
Illustration: arr[] = {1, 4, 5, 8, 11, 15, 21, 45, 70, 100}, array size(M) = 10, target = 45, base(N) = 3
Steps:
- Compute first power(power) of 3 (Base) greater than 10 (M), power = 27 in this case.
- Initialize a final index(finId) as 0 (position in arr[] where target value should be at the end).
- Now iterate through the powers of 3 (Base) that are less or equal to 27 and add them to the index as fallowing:
- 1st iteration : finId = 0. power is 27 and can’t be used because finId + power > M. So, finId = 0.
- 2nd iteration : finId = 0. power is 9 and can’t be used because element at finId + power > target
i.e. arr[finId + power] > target. So finId = 0. - 3rd iteration : finId = 0. power is 3, this time power can be used because arr[finId + power] < target. Now count how many times 3 can be added to finId. In this case 3 can sum two times. finId after 3rd iteration will be 6 (finId += 3 + 3). 3 can’t be added more than 2 times because finId will pass the index where target value is. So finId = 0 + 3 + 3 = 6.
- 4th iteration : finId = 6. power is 1, power can be used because arr[finId + power] ≤ target(45). Again count how many times 1 can be used. In this case 1 can be used only once. So add 1 only once with finId. So, finId = 6+1 = 7.
- after 4th iteration power is 0 so exit the loop.
- arr[7] = target. So the value is found at index 7.
笔记:
- 在每次迭代中,可以使用最大(Base – 1)次功率
- 基数可以是从 2 开始的任何正整数
- 需要对数组进行排序以执行此搜索算法
下面是上述方法的实现(与经典的二分搜索算法相比):
C++
// C++ code to implement the above approach
#include
using namespace std;
#define N 3
#define PowerOf2 4
int Numeric_Base_Search(int arr[], int M,
int target){
unsigned long long i, step1,
step2 = PowerOf2, times;
// Find the first power of N
// greater than the array size
for (step1 = 1; step1 < M; step1 *= N);
for (i = 0; step1; step1 /= N)
// Each time a power can be used
// count how many times
// it can be used
if (i + step1 < M && arr[i + step1]
<= target){
for (times = 1; step2;
step2 >>= 1)
if (i +
(step1 * (times + step2))
< M &&
arr[i +
(step1 * (times + step2))]
<= target)
times += step2;
step2 = PowerOf2;
// Add to final result
// how many times
// can the power be used
i += times * step1;
}
// Return the index
// if the element is present in array
// else return -1
return arr[i] == target ? i : -1;
}
// Driver code
int main(){
int arr[10] =
{1, 4, 5, 8, 11, 15, 21, 45, 70, 100};
int target = 45, M = 10;
int answer = Numeric_Base_Search(arr, M, target);
cout<
Java
// Java code to implement the above approach
class GFG {
static int N = 3;
static int PowerOf2 = 4;
static int Numeric_Base_Search(int[] arr, int M,
int target)
{
int i, step1, step2 = PowerOf2, times;
// Find the first power of N
// greater than the array size
for (step1 = 1; step1 < M; step1 *= N)
;
for (i = 0; step1 > 0; step1 /= N) {
// Each time a power can be used
// count how many times
// it can be used
if (i + step1 < M && arr[i + step1] <= target) {
for (times = 1; step2 > 0; step2 >>= 1)
if (i + (step1 * (times + step2)) < M
&& arr[i
+ (step1 * (times + step2))]
<= target)
times += step2;
step2 = PowerOf2;
// Add to final result
// how many times
// can the power be used
i += times * step1;
}
}
// Return the index
// if the element is present in array
// else return -1
return arr[i] == target ? i : -1;
}
// Driver code
public static void main(String args[])
{
int[] arr = { 1, 4, 5, 8, 11, 15, 21, 45, 70, 100 };
int target = 45, M = 10;
int answer = Numeric_Base_Search(arr, M, target);
System.out.println(answer);
}
}
// This code is contributed by Saurabh Jaiswal
Python3
# Python code for the above approach
N = 3
PowerOf2 = 4
def Numeric_Base_Search(arr, M, target):
i = None
step1 = None
step2 = PowerOf2
times = None
# Find the first power of N
# greater than the array size
step1 = 1
while(step1 < M):
step1 *= N
i = 0
while(step1):
step1 = step1 // N
# Each time a power can be used
# count how many times
# it can be used
if (i + step1 < M and arr[i + step1] <= target):
times=1
while(step2):
step2 >>= 1
if (i + (step1 * (times + step2)) < M and arr[i + (step1 * (times + step2))] <= target):
times += step2;
step2 = PowerOf2;
# Add to final result
# how many times
# can the power be used
i += times * step1
# Return the index
# if the element is present in array
# else return -1
return i if arr[i] == target else -1
# Driver code
arr = [1, 4, 5, 8, 11, 15, 21, 45, 70, 100]
target = 45
M = 10
answer = Numeric_Base_Search(arr, M, target)
print(answer)
# This code is contributed by Saurabh Jaiswal
C#
// C# code to implement the above approach
using System;
class GFG {
static int N = 3;
static int PowerOf2 = 4;
static int Numeric_Base_Search(int[] arr, int M,
int target)
{
int i, step1, step2 = PowerOf2, times;
// Find the first power of N
// greater than the array size
for (step1 = 1; step1 < M; step1 *= N)
;
for (i = 0; step1 > 0; step1 /= N) {
// Each time a power can be used
// count how many times
// it can be used
if (i + step1 < M && arr[i + step1] <= target) {
for (times = 1; step2 > 0; step2 >>= 1)
if (i + (step1 * (times + step2)) < M
&& arr[i
+ (step1 * (times + step2))]
<= target)
times += step2;
step2 = PowerOf2;
// Add to final result
// how many times
// can the power be used
i += times * step1;
}
}
// Return the index
// if the element is present in array
// else return -1
return arr[i] == target ? i : -1;
}
// Driver code
public static void Main()
{
int[] arr = { 1, 4, 5, 8, 11, 15, 21, 45, 70, 100 };
int target = 45, M = 10;
int answer = Numeric_Base_Search(arr, M, target);
Console.WriteLine(answer);
}
}
// This code is contributed by ukasp.
Javascript
7
时间复杂度: O(log N M * 记录2 N)
辅助空间: O(1)