Search code examples
pythonalgorithmoptimizationdata-structuresbit-shift

Calculate circular shift pairs in a list


A circular shift moves some of the digits in a number to the beginning of the number, and shifts all other digits forward to the next position. For example, all of the circular shifts of 564 are 564, 645, 456.

Lets say two numbers of equal length a and b are circular pairs if a can become b via circular shifting. Using the example above, the circular pairs of 564 are 645 and 456.

Given an array of positive integers nums, count the number of circular pairs i and j where 0 <= i < j < len(nums)

For example, circular_shifts([13, 5604, 31, 2, 13, 4560, 546, 654, 456]) should return 5. With the pairs being (13, 31), (13, 13), (5604, 4560), (31, 13), (546, 654).

I wrote a brute force solution that saves all circular shifts of a number in a dictionary shifts and for every number num in nums, I check all the following numbers and if a number num2 the same digits as num, I see if num2 is in num's circular shifts. If it is then I added this to the total count.

Unfortunately this algorithm runs too slowly and times out, I'm looking for a faster way to solve this problem can anyone think of optimizations, clever tricks, or other strategies to speed this up?


Solution

  • Not very elegant as not much time but the following should be faster as does not repeatedly access the list. Shifting is done on string for simplicity.

    from collections import Counter
    
    def big(num):
        max = num
        s = str(num)
        for _ in s:
            x = int(s[-1] + s[0:-1])
            if x > max:
                max = x
        return max
            
    circs = [big(z) for z in mylist]
    
    c = Counter(circs)
    
    total = 0
    for i in c:
        if c[i] > 1:
            total += c[i]
    print(total)