|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
×
作者:微信文章
刚看到个贴子,说一段AI生成的RAG知识库代码因为跨库事务锁冲突上线即崩,责任最后落在“人工复核不仔细”。贴主在评审会上提了隐患,但被CTO一句“别太保守”怼了下去。
我觉得这事吧,说到底不是AI不靠谱,而是人对AI的期望太高。AI能提高效率没错,但它不是超人,更不是甩锅的挡箭牌。CTO的立场可以理解,但跳过问题讨论、过度信任机器,最后翻车只能说是“技术乐观主义”过了头。
网友们提到“评审就该签字”“要静态分析”都没错,但风险意识才是根本,宏观地提风险不等于没指出问题,是会的人就该顺着提醒往下扒。
从我的角度看,AI写代码没问题,关键还是人得兜底。别拿AI当护身符,该负的责任不能推。技术再好,也不能代替经验和判断力。
总的来说还是要敬畏系统复杂度,不然踩坑只是时间问题。(备注:文末可领最新资料)
算法题:切分数组
这题说难不难,说简单也不简单,属于那种“你要是没思路就彻底懵了,有点思路就一下豁然开朗”的经典算法题型。
题目意思其实挺直白:给你一个数组 nums,你得把它切成几个子数组,每段的头尾两个数的最大公约数(GCD)得大于1。你得找出切出来的最少个数,也就是说,能合并就别乱切,别手欠一刀切下去发现其实还能合并的,那就亏了。
我们来一点点拆解这个逻辑。
首先,GCD这玩意儿不是你我说了算,它得两个数在质因数上有交集才能大于1。也就是说,数组里面那些互质的数就会成为“绊脚石”,让你不得不在它前面或者后面切一刀。
那问题来了,怎么判断哪些数能连在一起,哪些不能?
你可能第一反应是暴力搞,每一段都枚举所有可能的组合,然后取最大公约数判断是否满足条件。这种做法吧,思路上没问题,就是太暴力了点。假如数组长点,一下就爆时间了。
我这里提供一个更聪明的做法,稍微绕点弯子,但确实高效,而且不难理解。
我们可以用一个技巧性的优化方案,叫做“质因数分解 + 动态规划”。这听起来好像有点高深,但其实就是在搞一件事:你在遍历数组的时候,记录以每个“质因数”结尾的最小切分次数。用个数组来存,比如 dp[p] 表示以质因数 p 为结尾的最少切分数。
每次遇到一个数 num,我们先把它分解出所有的质因数(比如 6 分解成 2 和 3),然后看在这些质因数上,谁能接得上之前的子数组。如果某个质因数在前面已经出现过了,那我们就可以以它为“桥梁”继续延续之前的段落,不用切。如果都不能接,那就得切一刀。
说白了就是在维护一组质因数的“断点”,谁能衔接前面的段落,就说明可以合并。
下面我贴一份我写的 C 语言代码,兄弟们可以直接上手试试:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAX 100001
#define MAX_P 1000
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int primes[MAX], is_prime[MAX];
int dp[MAX];
int get_primes(int n) {
int count = 0;
for (int i = 2; i <= n; ++i) {
if (!is_prime) {
primes[count++] = i;
for (int j = i + i; j <= n; j += i) {
is_prime[j] = 1;
}
}
}
return count;
}
int min(int a, int b) {
return a < b ? a : b;
}
int split_array(int* nums, int numsSize) {
int ans = 0;
int prime_dp[MAX];
memset(prime_dp, 0x3f, sizeof(prime_dp));
int total_primes = get_primes(100000);
for (int i = 0; i < numsSize; ++i) {
int num = nums;
int minCut = ans + 1;
int backup[10];
int backCnt = 0;
for (int j = 0; j < total_primes && primes[j] * primes[j] <= num; ++j) {
if (num % primes[j] == 0) {
while (num % primes[j] == 0) num /= primes[j];
minCut = min(minCut, prime_dp[primes[j]]);
backup[backCnt++] = primes[j];
}
}
if (num > 1) {
minCut = min(minCut, prime_dp[num]);
backup[backCnt++] = num;
}
if (minCut == 0x3f3f3f3f) minCut = ans + 1;
for (int j = 0; j < backCnt; ++j) {
prime_dp[backup[j]] = minCut;
}
ans = minCut;
}
return ans;
}
int main() {
int nums[] = {2, 3, 6, 9, 5};
int size = sizeof(nums) / sizeof(nums[0]);
printf("最少可以切成 %d 个子数组\n", split_array(nums, size));
return0;
}
这段代码其实有点意思。它干的事情不多,但效率高,主要靠维护每个质因数对应的“切分次数”。你一看哪个质因数接得上,那就直接合并上去,不行就另起炉灶。
讲真,这题目最坑的一点是:你不能单纯只看前后两个数的GCD,更不能以为“连续两个能合并”就一定能一直合并到最后。中间可能某个数就卡住你了,让你不得不切。所以必须从“质因数层面”去理解这个切分的边界在哪,才能真正解决这个问题。
这种题我挺喜欢的,不是纯算法题,更像是在玩逻辑解谜游戏,你得找出一个抽象层次更高的维度去分析“可合并性”,而不是一味地暴力枚举。
最后我留个思考题给你们:如果允许数组中某些数被跳过(也就是可以删掉部分数),你觉得这个问题还能怎么变形?有没有更好的策略?这题一旦加点“可选项”,场面可能就更精彩了。欢迎大家留言交流哈~
-END-
我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html
🔥虎哥私藏精品🔥
虎哥作为一名老码农,整理了全网最全《最全项目实战源码及视频》。总量高达650GB,点击下方公众号回复关键字 php全部免费领取 |
|