Union-find: largest component size by common factor algorithm gives different results on every run

71 views Asked by At

I was practicing data structure algorithm and made a Union - Find solution for the question.

The problem is, I think the code seems ok, but when I run it on Xcode playground, it shows different answers for the same input.

For example, I put an array [4, 6, 15, 35] in the function largestComponentSize, then it shows 2, 3, or 4 as the answer. I don't understand what's happening behind.

class Solution {
    var uf = UnionFind()
    
    func largestComponentSize(_ nums: [Int]) -> Int {
        var maxNum:Int = 0
        var numFactorMap = [Int:Int]()
        var factorAdded = Set<Int>()
        for num in nums {
            var pFactors = getPrimeFactors(num)
            numFactorMap[num] = pFactors[0]
            for (i, val) in pFactors.enumerated() {
                if !factorAdded.contains(val) {
                    uf.addSet(val)
                    factorAdded.insert(val)
                }
                if i > 0 {
                    uf.union(pFactors[i-1], val)
                }
            }
        }
        
        var groupCountMap = [Int:Int]()
        
        for num in nums {
            var groupId = uf.find(numFactorMap[num]!)!
            if groupCountMap.keys.contains(groupId) {
                groupCountMap[groupId]! += 1
            } else {
                groupCountMap[groupId] = 1
            }
            maxNum = max(maxNum, groupCountMap[groupId]!)
        }
        
        return maxNum
    }

    func getPrimeFactors(_ num: Int) -> [Int] {
        var ans:Set<Int> = []

        if num == 1 {
            return []
        }
        
        var crrNum = num
        var deno = 2
        while crrNum >= deno {
            if crrNum % deno == 0 {
                ans.insert(deno)
                crrNum = crrNum / deno
            } else {
                deno = deno + 1
            }
        }
        
        return Array(ans)
    }
    
    class UnionFind {
        var index = [Int: Int]()
        var parent: [Int]
        var size: [Int]
        
        init() {
            parent = []
            size = []
        }
        
        func addSet(_ ele: Int) {
            index[ele] = parent.count
            parent.append(parent.count)
            size.append(1)
        }
        
        func getSetSize(_ ele: Int) -> Int {
            if let found = find(ele) {
                return size[found]
            }
            return 0
        }
        
        func find(_ ele: Int) -> Int? {
            if let indexOfEle = index[ele] {
                if parent[indexOfEle] == indexOfEle {
                    return indexOfEle
                } else {
                    if let found = find(parent[indexOfEle]) {
                        parent[indexOfEle] = found
                    }
                    return parent[indexOfEle]
                }
            } else {
                return nil //never come here
            }
        }
        
        func union(_ first: Int, _ second: Int) {
            guard let indexOfFirst = index[first], let indexOfSecond = index[second] else {
                return
            }
            
            if parent[indexOfFirst] == parent[indexOfSecond] {
                return
            }
            
            var indexOfLarger = indexOfFirst
            var indexOfSmaller = indexOfSecond
            if size[indexOfFirst] < size[indexOfSecond] {
                indexOfLarger = indexOfSecond
                indexOfSmaller = indexOfFirst
            }
            
            parent[indexOfSmaller] = indexOfLarger
            size[indexOfLarger] += size[indexOfSmaller]
            
            return
        }
    }
}

var sol = Solution()
var nums = [4, 6, 15, 35]
var ans = sol.largestComponentSize(nums)

Thank you for your help in advance!

I just tried it on Xcode playground.

0

There are 0 answers