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

Swift中使用回溯算法实现砝码配重问题遇阻,求排查解决

Hey there! Let's break down why your current code only works for some inputs, then build a proper backtracking solution (plus a bonus optimized method since your weight set has a unique, pattern-based structure).

The Problem With Your Current Code

Your snippet is doing a greedy linear scan—just adding weights in order if they're smaller than the target—instead of implementing backtracking's core "try, check, backtrack" logic. This fails because:

  • You might overshoot the target by adding small weights first (e.g., trying to make 9 by adding 1+2+7 gives 10, which is too big, but the correct combo is 2+7)
  • There's no way to "undo" a weight selection to try a different combination
  • You're not recursively checking if the remaining target can be met with the remaining weights

Proper Backtracking Implementation

Backtracking works by selecting a weight, recursively checking if the remaining target can be fulfilled with the remaining weights, and if not, undoing the selection (backtracking). We'll sort weights from largest to smallest first to reduce unnecessary recursive branches:

func findWeightCombination(target: Int, weights: [Int]) -> [Int]? {
    var result: [Int]?
    var currentCombo: [Int] = []
    // Sort weights descending to minimize recursive steps
    let sortedWeights = weights.sorted(by: >)
    
    func backtrack(remainingTarget: Int, startIndex: Int) {
        // Base case: we've hit the exact target
        guard remainingTarget != 0 else {
            result = currentCombo
            return
        }
        // Stop if we already found a valid combo
        guard result == nil else { return }
        
        // Iterate through weights starting from startIndex to avoid duplicate combos
        for i in startIndex..<sortedWeights.count {
            let weight = sortedWeights[i]
            // Skip weights larger than what we still need
            guard weight <= remainingTarget else { continue }
            
            // Try using this weight
            currentCombo.append(weight)
            // Recurse with the reduced target, starting from the next weight (no reusing)
            backtrack(remainingTarget: remainingTarget - weight, startIndex: i + 1)
            // Backtrack: remove the weight if it didn't lead to a solution
            currentCombo.removeLast()
        }
    }
    
    backtrack(remainingTarget: target, startIndex: 0)
    // Return sorted combo to match your example format
    return result?.sorted()
}

// Test it out!
let weights = [1,2,7,10,20,70,100,200,700]
print(findWeightCombination(target: 12, weights: weights) ?? []) // [2, 10]
print(findWeightCombination(target: 8, weights: weights) ?? []) // [1, 7]
print(findWeightCombination(target: 9, weights: weights) ?? []) // [2, 7]
print(findWeightCombination(target: 13, weights: weights) ?? []) // [1, 2, 10]

Bonus: Optimized Solution (No Backtracking Needed!)

Your weight set follows a specific pattern: it's grouped by powers of 10 ([1,2,7], [10,20,70], [100,200,700], etc.). Each group can make any digit 1-3,7-9 with addition (digits 4-6 can't be made with addition, so we return nil for those). We can leverage this to skip backtracking entirely and solve the problem in linear time:

func findWeightCombinationFast(target: Int, weights: [Int]) -> [Int]? {
    var result: [Int] = []
    var remaining = target
    var divisor = 1
    
    while remaining > 0 {
        let digit = remaining % 10
        let baseWeights = [1*divisor, 2*divisor, 7*divisor]
        
        switch digit {
        case 1: result.append(baseWeights[0])
        case 2: result.append(baseWeights[1])
        case 3: result.append(contentsOf: [baseWeights[0], baseWeights[1]])
        case 7: result.append(baseWeights[2])
        case 8: result.append(contentsOf: [baseWeights[0], baseWeights[2]])
        case 9: result.append(contentsOf: [baseWeights[1], baseWeights[2]])
        default: // Digits 0,4,5,6 can't be made with addition
            return nil
        }
        
        remaining /= 10
        divisor *= 10
    }
    
    return result.sorted()
}

// Test the fast version
print(findWeightCombinationFast(target: 12, weights: weights) ?? []) // [2, 10]
print(findWeightCombinationFast(target: 8, weights: weights) ?? []) // [1, 7]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:27:03