Rotate Array in Swift

前端 未结 10 765
终归单人心
终归单人心 2021-01-05 16:45

While exploring algorithms in Swift, couldn\'t find algorithm for array rotation in swift without using funcs shiftLeft / shiftRight.

C has

相关标签:
10条回答
  • 2021-01-05 16:52

    This solution rotates the element of time complexity O(n)

    func rotLeft(a: [Int], d: Int) -> [Int] {
       var arr = a
       var size = arr.count - 1
       for i in 0...size  {
         let newloc = (i + (arr.count - d)) % arr.count
         arr[newloc] = a[i]
       }
       return arr
    }
    

    you shouldn't use .append(x) as in the worst case it can be O(n) and you shouldn't use .remove(at: x) as its O(n) when you can avoid using those methods As when using them you basically get n + n + n which isn't that great

    0 讨论(0)
  • 2021-01-05 16:56

    If anybody lands here after watching the Embracing Algorithms WWDC18 session by David Abrahams, here is one of the implementations of rotate from the swift/test/Prototypes/Algorithms.swift file.

    extension MutableCollection where Self: BidirectionalCollection {
        /// Rotates the elements of the collection so that the element
        /// at `middle` ends up first.
        ///
        /// - Returns: The new index of the element that was first
        ///   pre-rotation.
        /// **- Complexity: O(*n*)**
        @discardableResult
        public mutating func rotate(shiftingToStart middle: Index) -> Index {
            self[..<middle].reverse()
            self[middle...].reverse()
            let (p, q) = _reverseUntil(middle)
            self[p..<q].reverse()
            return middle == p ? q : p
            }
        }
    

    This algorithms depends on reverseUntil(:) defined in the same file

    extension MutableCollection where Self: BidirectionalCollection {
    
    /// Reverses the elements of the collection, moving from each end until
    /// `limit` is reached from either direction. The returned indices are the
    /// start and end of the range of unreversed elements.
    ///
    ///     Input:
    ///     [a b c d e f g h i j k l m n o p]
    ///             ^
    ///           limit
    ///     Output:
    ///     [p o n m e f g h i j k l d c b a]
    ///             ^               ^
    ///             f               l
    ///
    /// - Postcondition: For returned indices `(f, l)`:
    ///   `f == limit || l == limit`
    @inline(__always)
    @discardableResult
    internal mutating func _reverseUntil(_ limit: Index) -> (Index, Index) {
        var f = startIndex
        var l = endIndex
        while f != limit && l != limit {
            formIndex(before: &l)
            swapAt(f, l)
            formIndex(after: &f)
        }
        return (f, l)
    }
    }
        
    
    0 讨论(0)
  • 2021-01-05 16:57

    here is a way to rotate left or right. Just call rotate on your array as shown. This does not mutate the array, if you wish to mutate the array, set the array equal to the rotation.

    extension Array {
        func rotate(moveRight: Bool, numOfRotations: Int) -> Array<Element>{
            var arr = self
            var i = 0
            while i < numOfRotations {
                if moveRight {
                    arr.insert(arr.remove(at: arr.count - 1), at: 0)
                } else {
                    arr.append(arr.remove(at: 0))
                }
                i += 1
            }
            return arr
        }
    }
    
    var arr = ["a","b","c","d","e"]
    
    print(arr.rotate(moveRight: true, numOfRotations: 2))
    // ["d", "e", "a", "b", "c"]
    print(arr)
    // ["a", "b", "c", "d", "e"]
    arr = arr.rotate(moveRight: true, numOfRotations: 2)
    print(arr)
    // ["d", "e", "a", "b", "c"]
    
    
    0 讨论(0)
  • 2021-01-05 16:58

    Edit update:

    Swift 5 or later

    extension RangeReplaceableCollection {
        mutating func rotateLeft(positions: Int) {
            let index = self.index(startIndex, offsetBy: positions, limitedBy: endIndex) ?? endIndex
            let slice = self[..<index]
            removeSubrange(..<index)
            insert(contentsOf: slice, at: endIndex)
        }
    }
    

    extension RangeReplaceableCollection {
        mutating func rotateRight(positions: Int) {
            let index = self.index(endIndex, offsetBy: -positions, limitedBy: startIndex) ?? startIndex
            let slice = self[index...]
            removeSubrange(index...)
            insert(contentsOf: slice, at: startIndex)
        }
    }
    

    var test = [1,2,3,4,5,6,7,8,9,10]
    test.rotateLeft(positions: 3)   // [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
    
    var test2 = "1234567890"
    test2.rotateRight(positions: 3)   // "8901234567"
    
    0 讨论(0)
  • 2021-01-05 16:58

    To be complete, the rotation function should support negative (right) rotations and rotating more than the array's size

    extension Array 
    {
        mutating func rotateLeft(by rotations:Int) 
        { 
           // rotation irrelevant when less than 2 elements
           if count < 2 { return }  
    
           // effective left rotation for negative and > count
           let rotations = (rotations%count + count) % count 
    
           // no use rotating by zero
           if rotations == 0 { return } 
    
           // rotate
           (1..<count).reduce(0)
           { let i = ($0.0+rotations)%count; swap(&self[$0.0],&self[i]); return i }
        }
    
        mutating func reverse()
        {
           (0..<count/2).forEach{ swap(&self[$0],&self[count-$0-1]) }
        }
    }
    
    0 讨论(0)
  • 2021-01-05 17:04

    // a is the array to be left rotated // d is the number of unit for left rotation

    func rotLeft(a: [Int], d: Int) -> [Int] {
        var a = a
        for index in 0...(d - 1) {
           a.append(a[0])
           a.remove(at: 0)
         }
        return a
     }
    

    // calling Function

    rotLeft(a: [1,2,3,4,5], d: 4)
    

    // OutPut [5, 1, 2, 3, 4]

    0 讨论(0)
提交回复
热议问题