突破编程_C++_查找算法(斐波那契查找)

1 算法题 :使用斐波那契查找算法在有序数组中查找指定元素

1.1 题目含义

使用斐波那契查找算法在有序数组中查找指定的元素。斐波那契查找算法是一种基于斐波那契数列的查找算法,主要用于有序数组的查找。该算法将斐波那契数列与二分查找的思想相结合,从而提高查找效率。

斐波那契数列是这样的一个数列:0、1、1、2、3、5、8、13、21、34、…,其中每个数字是前两个数字的和。斐波那契查找算法利用斐波那契数列的性质,将数组分为两部分,如果目标值在前半部分,则在前半部分继续查找;如果目标值在后半部分,则在后半部分继续查找。当数组的长度不是斐波那契数时,算法会对数组长度进行适当的扩展(通常是增加元素,保证可以整除),并在查找完成后恢复数组原样。

注意:在实际编程实现时,斐波那契查找算法可能需要处理一些边界情况,如当数组为空或只包含一个元素时,以及当目标值超出数组范围时。此外,由于斐波那契查找算法可能需要对数组进行扩展,因此在实际应用中可能需要对原始数组进行备份,以便在查找完成后恢复其原样。

1.2 示例

示例 1:
输入:

  • nums = [1, 3, 4, 7, 10, 12, 15, 18, 20, 25, 30]
  • target = 7

输出:

  • 3

说明:

  • 因为元素 7 在数组中的索引是 3。

示例 2:
输入:

  • nums = [1, 3, 4, 7, 10, 12, 15, 18, 20, 25, 30]
  • target = 2

输出:

  • -1

说明:

  • 2 不存在于 nums 中,返回 -1。

示例 3:
输入:

  • nums = []
  • target = 0

输出:

  • -1

说明:

  • nums 为空,0 不存在于 nums 中,返回 -1。

2 解题思路

2.1 循环遍历实现

(1)初始化:

  • 接收有序数组和目标值作为输入。
  • 计算数组长度 n。
  • 找到大于或等于n的最小斐波那契数F,这通常涉及计算斐波那契数列直到找到合适的数。
  • 如果数组长度不是斐波那契数,则可能需要在数组末尾添加额外的元素(通常使用数组最后一个元素填充),以确保数组长度等于斐波那契数。

(2)定义斐波那契数列相关变量:

  • 计算前两个斐波那契数 fibMMinus1 和 fibM(通常初始化为 0 和 1)。
  • 后续斐波那契数可以通过迭代计算得到,直至达到或超过数组长度n。

(3)进行斐波那契查找:

  • 初始化两个指针 low 和 high,分别指向数组的起始和结束位置。
  • 当 low 小于等于 high 时执行循环:
    • 计算 mid,即 low 和 high 之间的斐波那契分割点。
    • 如果目标值等于数组中的 mid 位置的元素,返回 mid。
    • 如果目标值小于 mid 位置的元素,则在数组的左半部分继续查找,更新 high 为 mid - 1。
    • 如果目标值大于 mid 位置的元素,则在数组的右半部分继续查找,更新 low 为 mid + 1。

(4)处理边界情况:

  • 如果循环结束仍未找到目标值,则目标值不在数组中,返回 -1。

(5)恢复数组:

  • 如果在步骤 1 中扩展了数组,现在需要移除添加的额外元素,恢复数组原样。

(6)结束:

  • 返回查找到的目标值的索引或 -1(如果未找到)。

2.2 递归实现

(1)初始化:

  • 接收有序数组 arr、目标值 target、数组长度n作为输入。
  • 初始化斐波那契数列中的两个关键数 fibMMinus2 和 fibMMinus1 为 0 和1。
  • 根据数组长度 n,递归计算斐波那契数列中大于等于 n 的最小数 fibM。

(2)递归计算斐波那契数:

  • 定义一个递归函数 fibonacci(int n),用于计算斐波那契数列中第n个数。
  • 在函数内部,如果 n 等于 0 或 1,直接返回 n(斐波那契数列的前两个数)。
  • 否则,递归调用f ibonacci(n-1) 和 fibonacci(n-2),并将它们的和作为当前斐波那契数返回。

(3)扩展数组:

  • 如果数组长度 n 不是斐波那契数,通过复制最后一个元素来扩展数组,使其长度达到 fibM。

(4)递归查找:

  • 定义一个递归查找函数 fibonacciSearch(int arr[], int low, int high, int target)。
  • 在函数内部,计算中间位置 mid,该位置为 low + fibMMinus2。
  • 如果 mid 越界(即 mid >= high),则调整 mid 为 high - 1。
  • 如果目标值 target 等于 arr[mid],返回 mid。
  • 如果 target 小于 arr[mid],递归调用 fibonacciSearch 在数组的左半部分查找,更新 high 为 mid - 1。
  • 如果 target 大于 arr[mid],递归调用 fibonacciSearch 在数组的右半部分查找,更新 low 为 mid + 1,并且更新 fibMMinus2 和 fibMMinus1 为斐波那契数列中较小的两个数。

(5)处理未找到的情况:

  • 如果递归查找函数返回 -1,说明目标值不在数组中,直接返回 -1。

(6)恢复数组:

  • 如果在步骤 3 中扩展了数组,现在需要移除添加的额外元素,恢复数组原样。

(7)返回结果:

  • 返回递归查找函数的结果,即目标值在数组中的索引,或者 -1(如果未找到)。

3 算法实现代码

3.1 循环遍历实现

如下为算法实现代码:

#include <iostream>  
#include <vector>  

// 计算斐波那契数列中大于等于n的最小数  
int fibonacci(int n) {
	if (n <= 1) return n;
	int a = 0, b = 1, c;
	while (a < n) {
		c = a + b;
		a = b;
		b = c;
	}
	return b;
}

class Solution
{
public:
	// 斐波那契查找算法  
	int fibonacciSearch(const std::vector<int>& arr, int target) {
		int n = arr.size();
		if (n == 0) return -1; // 空数组,直接返回-1  

		int fibM = fibonacci(n); // 计算斐波那契数列中大于等于n的最小数  

		// 扩展数组,确保长度为斐波那契数  
		std::vector<int> temp(fibM);
		for (int i = 0; i < n; ++i) {
			temp[i] = arr[i];
		}
		for (int i = n; i < fibM; ++i) {
			temp[i] = arr[n - 1]; // 用最后一个元素填充  
		}

		int low = 0, high = fibM - 1;
		int mid, index = -1;
		int fibMMinus1 = 0, fibMMinus2 = 1;

		while (low <= high) {
			mid = low + fibMMinus2; // 防止mid过大越界  
			if (mid >= high) {
				mid = high;
			}

			if (temp[mid] > target) {
				high = mid - 1;
				fibMMinus2 = fibMMinus1;
				fibMMinus1 = mid;
			}
			else if (temp[mid] < target) {
				low = mid + 1;
				fibMMinus1 = fibMMinus1 + fibMMinus2;
				fibMMinus2 = fibMMinus1 - fibMMinus2;
			}
			else {
				index = mid;
				break;
			}
		}

		// 如果找到了目标值,需要将其映射回原数组中的位置  
		if (index != -1 && index < n) {
			return index;
		}

		return -1; // 未找到目标值  
	}
};

这段代码首先定义了一个辅助函数 fibonacci 来计算斐波那契数列中大于等于数组长度n的最小数。然后在 fibonacciSearch 函数中,扩展了数组以确保其长度是斐波那契数,并初始化了斐波那契查找所需的相关变量。接下来,使用循环进行查找,并根据比较结果调整 low 和 high 的边界以及斐波那契数列的相关值。如果找到目标值,则将其映射回原数组中的位置并返回;否则,返回 -1 表示未找到目标值。

调用上面的算法,并得到输出:

int main() 
{
	Solution s;

	std::vector<int> arr = { 1, 3, 4, 7, 10, 12, 15, 18, 20, 25, 30 };
	int target = 7;

	int index = s.fibonacciSearch(arr, target);
	if (index != -1) {
		std::cout << "Element found at index: " << index << std::endl;
	}
	else {
		std::cout << "Element not found in the array." << std::endl;
	}

	return 0;
}

上面代码的输出为:

Element found at index: 3

3.2 递归实现

如下为算法实现代码:

#include <iostream>  
#include <vector>  

// 递归计算斐波那契数  
int fibonacci(int n) {
	if (n <= 1) return n;
	return fibonacci(n - 1) + fibonacci(n - 2);
}

class Solution
{
public:
	// 斐波那契查找算法  
	int fibonacciSearch(const std::vector<int>& arr, int target) {
		int n = arr.size();
		if (n == 0) return -1; // 空数组,直接返回-1  

		int fibM = fibonacci(n); // 计算斐波那契数列中大于等于n的最小数  

		// 初始化递归查找所需的斐波那契数  
		int fibMMinus1 = 0;
		int fibMMinus2 = 1;

		// 调用递归查找函数  
		return fibonacciSearchRecursive(arr, 0, n - 1, target, fibM, fibMMinus2, fibMMinus1);
	}

private:
	// 递归查找函数  
	int fibonacciSearchRecursive(const std::vector<int>& arr, int low, int high, int target, int fibM, int fibMMinus2, int fibMMinus1) {
		if (low > high) {
			return -1;
		}

		int mid = low + fibMMinus2;

		// 防止mid越界  
		if (mid >= high) {
			mid = high;
		}

		if (arr[mid] == target) {
			return mid;
		}

		if (arr[mid] > target) {
			return fibonacciSearchRecursive(arr, low, mid - 1, target, fibM, fibMMinus1, fibMMinus1 + fibMMinus2);
		}
		else {
			return fibonacciSearchRecursive(arr, mid + 1, high, target, fibM, fibMMinus2, fibMMinus1);
		}
	}
};

这段代码中首先定义了一个递归函数 fibonacci 来计算斐波那契数。然后,定义了递归查找函数 fibonacciSearchRecursive,它接收数组、查找范围(low 和 high)、目标值以及斐波那契数列中的三个数(fibM、fibMMinus2 和 fibMMinus1)作为参数。递归查找函数根据中间位置 mid 与目标值 target 的比较结果来缩小查找范围,并递归调用自身。

4 测试用例

以下是针对上面算法的测试用例,基本覆盖了各种情况:

(1)基础测试用例
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 9
输出:4
说明:目标值 9 存在于数组中,位于索引 4 的位置。

(2)目标值不存在于数组中
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 2
输出:-1
说明:目标值 2 不存在于数组中。

(3)目标值位于数组开头
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 -1
输出:0
说明:目标值 -1 位于数组的开头,即索引 0 的位置。

(4)目标值位于数组末尾
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 12
输出:5
说明:目标值 12 位于数组的末尾,即索引 5 的位置。

(5)目标值位于数组中间
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 3
输出:2
说明:目标值 3 位于数组的中间位置,即索引 2 的位置。

(6)空数组
输入:数组 [],目标值 9
输出:-1
说明:空数组不包含任何元素,因此无法找到目标值。

(7)数组只有一个元素
输入:数组 [9],目标值 9
输出:0
说明:数组只有一个元素,且该元素就是目标值,位于索引 0 的位置。

(8)数组中存在多个相同的目标值
输入:数组 [1, 2, 3, 3, 4, 5],目标值 3
输出:2 或 3
说明:数组中存在多个目标值 3,返回任意一个目标值的索引都是正确的。这里可以返回 2 或 3。

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值