You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中将k步最大排列算法优化至O(n)时间复杂度?

优化大规模数组的k次最大交换算法(R语言)

需求回顾

我们需要对一组数字执行最多k次两两交换,每次交换后都要得到当前能生成的最大排列;如果提前得到全局最大排列,就直接停止并输出结果。举个例子:

当k=2、数组为(1,4,2,5,3,3)时,第一步交换1和5得到(5,4,2,1,3,3),第二步交换2和3得到(5,4,3,1,3,2);如果k足够大(比如k=10),当数组变成全局最大排列(5,4,3,3,2,1)时就会提前停止。

现有代码的瓶颈

你提供的现有代码逻辑是每次找当前数组的最大值,定位其最右侧位置,再找左侧第一个更小的数交换。但问题在于:

  • 每次循环都调用sort()和which(),这些操作都是O(n)级别的;
  • 当k接近n、数组规模达到1e4时,整体时间复杂度会变成O(kn)≈O(n²),这显然会导致运行过慢。

O(n)时间复杂度的优化方案

要实现线性时间复杂度,我们需要提前预处理所有数字的位置,避免每次循环都遍历整个数组。核心思路是:从左到右逐个确定每个位置的最大可能数字,用预处理的位置信息快速找到需要交换的目标位置,同时跟踪剩余交换次数k。

具体实现代码

max_k_swap <- function(arr, k) {
  n <- length(arr)
  if (k <= 0) return(arr)
  
  # 预处理:从右到左记录每个数字的所有出现位置(方便取最右侧的索引)
  num_positions <- list()
  for (i in n:1) {
    num <- as.character(arr[i])
    if (is.null(num_positions[[num]])) {
      num_positions[[num]] <- c()
    }
    num_positions[[num]] <- c(num_positions[[num]], i)
  }
  
  # 降序排列所有唯一数字,方便从最大的开始尝试
  sorted_nums <- sort(unique(arr), decreasing = TRUE)
  current_num_idx <- 1
  current_max <- sorted_nums[current_num_idx]
  
  for (i in 1:n) {
    if (k <= 0) break
    
    current_val <- arr[i]
    # 当前位置已经是可用的最大数字,直接跳过并更新位置记录
    if (current_val == current_max) {
      # 移除当前位置(已使用)
      pos_list <- num_positions[[as.character(current_max)]]
      num_positions[[as.character(current_max)]] <- pos_list[pos_list != i]
      # 如果当前最大值已经用完,切换到下一个最大数字
      if (length(num_positions[[as.character(current_max)]]) == 0) {
        current_num_idx <- current_num_idx + 1
        if (current_num_idx > length(sorted_nums)) break
        current_max <- sorted_nums[current_num_idx]
      }
      next
    }
    
    # 找到当前最大数字的最右侧可用位置
    pos_list <- num_positions[[as.character(current_max)]]
    swap_pos <- pos_list[length(pos_list)]
    
    # 执行交换
    temp <- arr[i]
    arr[i] <- arr[swap_pos]
    arr[swap_pos] <- temp
    
    # 更新位置记录:
    # 1. 移除当前最大值的交换位置
    num_positions[[as.character(current_max)]] <- pos_list[-length(pos_list)]
    # 2. 更新原数字的位置(把swap_pos替换成i)
    temp_pos_list <- num_positions[[as.character(temp)]]
    temp_pos_list[temp_pos_list == swap_pos] <- i
    num_positions[[as.character(temp)]] <- temp_pos_list
    
    k <- k - 1
    
    # 如果当前最大值用完,切换到下一个最大数字
    if (length(num_positions[[as.character(current_max)]]) == 0) {
      current_num_idx <- current_num_idx + 1
      if (current_num_idx > length(sorted_nums)) break
      current_max <- sorted_nums[current_num_idx]
    }
  }
  
  arr
}

# 测试示例
test_arr <- c(1,4,2,5,3,3)
k_val <- 2
cat("k=2时的结果:", max_k_swap(test_arr, k_val), "\n")
# 输出:k=2时的结果: 5 4 3 1 3 2

# 测试提前达到全局最大的情况
k_large <- 10
cat("k=10时的结果:", max_k_swap(test_arr, k_large), "\n")
# 输出:k=10时的结果: 5 4 3 3 2 1

方案优势

  1. 预处理阶段:一次性遍历数组,记录每个数字的所有位置,时间复杂度O(n);
  2. 遍历过程:从左到右逐个确定位置,每次交换的查找和更新操作都是O(1)级别的;
  3. 整体复杂度:整个算法只需要两次线性遍历(预处理+主循环),时间复杂度严格为O(n),完全适合处理1e4甚至更大规模的数组。

内容的提问来源于stack exchange,提问作者Tony Hellmuth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:25:28