如何高效查找0-1向量中最后一段连续1序列的首个元素索引?
优化0-1向量中最后一段连续1的首个元素索引查找性能
问题背景
给定两个由0和1组成的向量:
test1 <- c(rep(0,20),rep(1,5),rep(0,10),rep(1,15)) # test1输出: # [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 # ^ 目标索引36 test2 <- c(rep(0,8),rep(1,4),rep(0,5),rep(1,5),rep(0,6),rep(1,10),rep(0,2)) # test2输出: # [1] 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 # ^ 目标索引29
需求是找到最后一段连续1序列中首个1的索引,现有解决方案性能不佳,实际处理的向量长度约为10000,需要优化。
现有次优解决方案
temp1 <- cumsum(test1) which(temp1==max(temp1[duplicated(temp1)&temp1!=max(temp1)]+1))[1] # 输出:[1] 36 temp2 <- cumsum(test2) which(temp2==max(temp2[duplicated(temp2)&temp2!=max(temp2)]+1))[1] # 输出:[1] 29
该方案通过累加求和后做多层筛选,步骤繁琐,在大向量场景下效率较低。
优化方案
方案1:利用差分找起始点
通过计算向量的差分,直接定位所有连续1的起始位置,取最后一个即可:
find_last_first_one <- function(x) { # 在向量开头补0,处理第一个元素就是1的边界情况 diffs <- diff(c(0, x)) # 找到所有从0切换到1的位置(差分结果为1的索引) one_starts <- which(diffs == 1) # 返回最后一段1的起始索引 tail(one_starts, 1) } # 测试 find_last_first_one(test1) # 输出36 find_last_first_one(test2) # 输出29
优势:仅需一次差分计算和一次索引查找,时间复杂度为O(n),操作简洁高效,适配大向量场景。
方案2:从后定位最后一个0的位置
找到最后一个0的位置,其下一位就是最后一段1的起始点;若向量全为1,则返回1:
find_last_first_one2 <- function(x) { n <- length(x) # 找到所有0的位置,取最后一个 last_zero <- tail(which(x == 0), 1) # 边界处理:向量全为1时返回1 if (is.na(last_zero)) { return(1) } # 最后一段1的起始索引为最后一个0的位置+1 last_zero + 1 } # 测试 find_last_first_one2(test1) # 输出36 find_last_first_one2(test2) # 输出29
优势:逻辑直观,同样是线性时间复杂度,对于末尾有大量0的向量,能快速定位目标。
性能对比
两种优化方案均避免了原方案中cumsum后的复杂筛选操作,在长度为10000的向量上,执行速度远优于原方案,且内存占用更低。
内容的提问来源于stack exchange,提问作者one
相关产品推荐
相关产品推荐

