拉格朗日插值
普通拉格朗日插值
众所周知,n+1 个横坐标互不相同的点可以确定出唯一的最高次为 n 的多项式。当给定你 n 个点并要求你求出横坐标为 x 的点的纵坐标,高斯消元虽是个选择,但是 O(n3) 的时间复杂度显然不优。于是我们选择用 O(n2) 的拉格朗日插值解决这类问题。
我们先来考虑构造一个函数 L(x),我们希望这个函数在 x=xi 时等于 1,在 x=xj(0≤j≤n,j≠i) 时等于 0。
我们想达到这个目的,不难想到去令多个式子相乘,这样的话只要有一项等于 0,则总的式子就等于 0。
所以我们先设 L(x)=∏0≤j≤n(x−xj),但是我们发现当 x=xi 时也等于 0。
所以我们再设 L(x)=∏0≤j≤n且i≠j(x−xj),但是我们发现当 x=xi 时不等于 1。
所以我们设 L(x)=∏0≤j≤n且i≠jx−xjxi−xj。
然后就得到了一个非常巧的函数。
然后就有:
f(x)=n∑i=0yiL(x)=n∑i=0yi∏j≠ix−xjxi−xj
这个式子显然是可以在 O(n2) 的时间复杂度内算出来的。
在横坐标连续的情况下的拉格朗日插值
当横坐标连续时,我们可以将 xi 看作 i,xj 看作 j,所以原式变成:
f(x)=n∑i=0yi∏j≠ix−ji−j
现在的重点在于如何快速算出 ∏j≠ix−ji−j
我们发现分子可以写成前缀积和后缀积相乘的形式,所以设 prei=i∏j=0(x−j),sufi=n∏j=i(x−j),然后分子就可以写成 prei−1×sufi+1。
但是我们发现,分子好像也可以不写成前缀积和后缀积相乘的形式。我们直接预处理出 prod=n∏j=0(x−j),然后分子就是 prodx−i,我们把 x−i 移到分母上即可。
我们发现分母可以写成阶乘的形式,所以设 faci 为 i 的阶乘,然后分母就可以写成 faci−1×facn−i。
但是我们发现,当 i<j 时有可能会使原式变为负数。我们考虑什么时候会出现这种情况。
对于 m 个负数相乘,当 m 为偶数时结果为正,m 为奇数时结果为负。对于一个 i,大于 i 的 j 的个数为 n−i,所以我们让分母再乘上 (−1)n−i 即可。
所以整合一下:
f(x)=n∑i=0yi×prei−1×sufi+1(−1)n−i×faci−1×facn−i=n∑i=0yi×prod(x−i)×(−1)n−i×faci−1×facn−i
我们发现这个式子是 O(n) 的。
重心拉格朗日插值
如果我们需要计算多次拉格朗日插值,那每一次都跑一边 O(n2) 这个过程是很不优的,因为我们重复算了很多东西。
所以我们考虑重写一下原式。
f(x)=n∑i=0yi∏j≠ix−xjxi−xj=n∑i=0yi∏j≠i(x−xj)∏p≠i1xi−xp=n∑i=0∏j≠i(x−xj)yi∏p≠i(xi−xp)=n∏j=0(x−xj)n∑i=0yi∏p≠i(xi−xp)×1x−xi
然后我们设 prodi=yi∏p≠i(xi−xp),gx=n∏j=0(x−xj)。
所以有:
f(x)=g(x)n∑i=0prodix−xi
在 O(n2) 预处理出 prod 后,这个式子可以 O(n) 计算。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现