斐波那契数列-编程求解方法大全

本文围绕斐波那契数列第n项的求解展开。先指出直接用递归会因重复计算导致栈溢出,接着介绍动态规划可避免重复计算,以一定空间代价使时间复杂度达O(n),还探讨了将递归与动态规划结合及另类解法等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源:我是码农,转载请保留出处和链接!

本文链接:http://www.54manong.com/?id=1232

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。

n<=39

直接上我的代码:

int Fibonacci(int n) {
        int sum =0,l=0,r=1;
        if(n==1)
            return 1;
        else
        {
            for(int i=0;i<n-1;i++)
            {
                sum=l+r;
                l=r;
                r=sum;
            }
        }
        return sum;
    }

 


这个题可以说是迭代(Iteration) VS 递归(Recursion),

f(n) = f(n-1) + f(n-2),第一眼看就是递归啊,简直完美的递归环境,递归肯定很爽,这样想着关键代码两三行就搞定了,注意这题的n是从0开始的:

1

2

if(n<=1return n;

else return Fibonacci(n-1)+Fibonacci(n-2);

然而并没有什么用,测试用例里肯定准备着一个超大的n来让Stack  Overflow,为什么会溢出?因为重复计算,而且重复的情况还很严重,举个小点的例子,n=4,看看程序怎么跑的:

Fibonacci(4) = Fibonacci(3) + Fibonacci(2);

                    = Fibonacci(2) + Fibonacci(1) + Fibonacci(1)  + Fibonacci(0);

                    = Fibonacci(1) + Fibonacci(0) + Fibonacci(1)  + Fibonacci(1) + Fibonacci(0);

由于我们的代码并没有记录Fibonacci(1)和Fibonacci(0)的结果,对于程序来说它每次递归都是未知的,因此光是n=4时f(1)就重复计算了3次之多。

那么如何求解呢,动态规划似乎不错,关于动态规划三个条件:最优子结构、无后效性、子问题重叠这些就不谈了,因为理(wo)论(ye)性(bu)太(tai)强(dong)了。

下例是一个简单的动态规划,以一定的空间代价避免代价更大的重复计算的栈空间浪费:

image.png

虽然看起来很蠢,空间浪费了sizeof(int)*(n-1),但是对于那个超大n的测试用例应该是可以通过了,时间复杂度也达到了O(n)。

那能不能把“优雅”的递归和动态规划结合起来呢?递归的优点在于便于理解和编码,而重复计算的关键原因在于代码里直接就“递”进去然后等着“归”了,所以避免重复的关键在于对子问题是否已经得出解的判断,即:

image.png

对于这种有很小范围内的计算,我们可以更暴力一点的。像下面这样:

public class Solution {

   public static int Fibonacci(int n) {

        int[] ns = {0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,

                 10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,

                 2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986};

         return ns[n];

     }

}

另类解法:

public int Fibonacci(int n) {

     if (n==0return 0;

     if (n <= 2) {

          return 1;

      }

      if (n == 3)

          return 2;

      int n1 = 1;

      int n2 = 2;

      for (int i = 4; i <= n; i++) {

          n1 ^= n2;

          n2 ^= n1;

          n1 ^= n2;

          n2 += n1;

 

      }

      return n2;

  }

代码量最少的解法:

public class Solution {

    public int Fibonacci(int n) {

        return n<=0 0 :n<=2 1 : Fibonacci(n-1) + Fibonacci(n-2);

    }

}

简单粗暴,拿走不谢!

下面这几个解法最牛逼,汇总了,真是逆天的操作:

// 遍历求解
function Fibonacci(n)
{
    var pre = 0;
    var num = 0;
    while (n > 0) {
        if (num == 0) {
            num = 1;
        } else {
            var tmp = num;
            num += pre;
            pre = tmp;
        }
 
        n--;
    }
 
    return num;
}
 
// 暴力求解
function Fibonacci2(n)
{
    var arr = [0,1,1,2,3,5,8,13,21,34,55,89,
    144,233,377,610,987,1597,2584,4181,6765,
    10946,17711,28657,46368,75025,
    121393,196418,317811,514229,832040,
    1346269,2178309,3524578,5702887,9227465,
    14930352,24157817,39088169,63245986];
    return arr[n];
}
 
// 通项公式求解
function Fibonacci3(n)
{
    if (n == 0) return 0;
    if (n == 1) return 1;
    if (n == 2) return 1;
 
    var sqrt5 = Math.sqrt(5);
    var result = 1 / sqrt5 * (Math.pow((1 + sqrt5) / 2, n) - Math.pow((1 - sqrt5) / 2, n));
    return Math.round(result);
}
<think>好的,我需要回答用户关于Vue3高级技巧、不常见用法和最佳实践的问题。用户之前提到过引用了一些资料,但那些引用似乎和Vue3关系不大,甚至可能有误导,比如引用[1]提到了快速排序,这明显是算法内容,和Vue无关。不过用户现在明确询问Vue3的高级技巧,所以需要抛开那些不相关的引用,专注于正确的知识点。 首先,我应该回忆Vue3的一些高级特性。比如Composition API的深入使用,响应式系统的底层原理,自定义指令的高级应用,还有组件方面的优化技巧,如递归组件、动态组件、异步组件等。此外,还有一些性能优化的方法,比如使用v-once、v-memo,或者利用Teleport和Suspense组件来优化DOM结构和加载状态。 接下来,需要整理这些知识点,确保准确性和实用性。例如,Composition API中的自定义hook可以封装可复用的逻辑,这可能是一个不常见但实用的技巧。另外,响应式方面,使用shallowRef和markRaw来优化性能,避免不必要的响应式追踪,这也是高级用法之一。 还要考虑到组件通信的高级方法,比如使用provide/inject结合Symbol作为键,确保注入的安全性。另外,模板引用(ref)的动态使用,尤其是在循环或条件渲染中,可能有些用户不太熟悉。 异步组件的懒加载和代码分割也是性能优化的重要部分,可以结合defineAsyncComponent和Webpack的动态导入来实现。Teleport组件用于将子节点渲染到DOM中的其他位置,这在处理模态框或通知时非常有用,但可能被忽视。 另外,自定义指令的高级用法,比如创建防抖点击指令,或者集成第三方库如GSAP,这也是值得提及的。还有,基于Vue3的TypeScript支持,如何利用泛型和类型推断来增强代码的健壮性,可能属于最佳实践的一部分。 需要验证每个技巧的正确性,比如v-memo的使用场景,确保在大型列表中的正确应用。递归组件的使用,需要命名组件的重要性,避免无限循环的问题。动态组件的:is绑定,可能需要结合keep-alive来保持状态。 最后,整理这些内容,分点说明,确保结构清晰,语言简洁,符合用户要求的中文回答,并生成相关问题。检查是否有遗漏的重要技巧,比如渲染函数的JSX用法,或者使用Composition API替代Mixins的优势,这些都是Vue3推荐的最佳实践。</think>### Vue3 高级技巧与不常见用法解析 #### 一、组件深度控制技巧 1. **递归组件命名强制要求** Vue3 要求递归组件必须显式声明 `name` 选项,否则会导致栈溢出: ```javascript export default { name: 'TreeItem', // 必须显式命名 template: `<div><TreeItem v-for="item in children"/></div>` } ``` 2. **动态组件状态保持** 使用 `<KeepAlive>` 包裹动态组件时,配合 `:include` 属性精准控制缓存策略: ```vue <KeepAlive :include="['TabA', 'TabC']]"> <component :is="currentComponent"/> </KeepAlive> ``` #### 二、响应式系统高级用法 1. **非深度响应式控制** 使用 `shallowRef` + `triggerRef` 实现手动触发更新: ```javascript const state = shallowRef({ count: 0 }) // 修改不会自动触发更新 state.value.count++ // 手动触发更新 triggerRef(state) ``` 2. **冻结大型数据集** 通过 `markRaw` 避免不必要响应式追踪: ```javascript const heavyData = markRaw(fetchBigData()) ``` #### 三、模板编译黑科技 1. **v-memo 性能优化** 在大型列表渲染中精准控制更新范围: ```vue <div v-for="item in list" :key="item.id" v-memo="[item.id === selectedId]"> {{ item.content }} </div> ``` 2. **内联模板(SSR场景)** Server Side Render 中特殊用法: ```vue <script type="text/x-template" id="custom-template"> <div>{{ dynamicContent }}</div> </script> ``` #### 四、Composition API 进阶 1. **Effect作用域控制** 使用 `effectScope` 批量管理副作用: ```javascript const scope = effectScope() scope.run(() => { watch(data, () => { /*...*/ }) watchEffect(() => { /*...*/ }) }) // 批量清理 scope.stop() ``` 2. **自定义 Ref 工厂** 创建带校验逻辑的 ref: ```javascript function validatedRef(value, validator) { return customRef((track, trigger) => ({ get() { track(); return value }, set(newVal) { if (validator(newVal)) { value = newVal trigger() } } })) } ``` #### 五、渲染函数妙用 1. **JSX 片段加速开发** 结合 TypeScript 的类型推断: ```tsx render() { return (<> <NavBar/> <main>{this.content}</main> </>) } ``` 2. **动态插槽生成器** 使用 `h()` 函数创建动态插槽内容: ```javascript render() { return h(MyComponent, {}, { default: () => [h('div', this.dynamicContent)] }) } ``` #### 六、性能优化实践 1. **组件懒加载策略** 配合 Suspense 实现分段加载: ```javascript const HeavyComponent = defineAsyncComponent({ loader: () => import('./Heavy.vue'), timeout: 3000, suspensible: true }) ``` 2. **Web Worker 集成** 通过 `worker-plugin` 实现 CPU 密集型任务分流: ```javascript const worker = new ComlinkWorker(new URL('./worker.js', import.meta.url)) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值