# 457 - Circular Array Loop

中間過程

Trial 1

一開始嘗試了自己的 fast & slow pointer 解法,可惜這個解法沒有辦法處理 [3,1,2] 這種從 index 0 無法走到 loop 起點的 case。

class Solution {
public:
    bool circularArrayLoop(vector<int>& nums) {
        if(nums.size() < 2) return false;

        // Find the loop
        int slow = 0, fast = 0;

        do {
            slow = (slow + nums[slow]) % nums.size();
            fast = (fast + nums[fast]) % nums.size();
            fast = (fast + nums[fast]) % nums.size();
        }while(slow != fast);

        // Calculate the length, if length <= 1, return false
        int l = 0;
        do {
            slow = (slow + nums[slow]) % nums.size();
            ++l;
        }while(slow != fast);

        if(l <= 1) return false;

        // Check forward or backward, if two directions, return false
        bool positive = false, negative = false;
        do {
            if(nums[slow] > 0) positive = true;
            else negative = true;

            if(positive & negative) return false;
            a
            slow = (slow + nums[slow]) % nums.size();
        }while(slow != fast);

        return true;
    }
};

Trial 2

我們可以把上面的解法變成對每個 index 都當作開頭,雖然要花 O(n^2) 的時間,但至少可以解掉 [3,1,2] 這種 case。

class Solution {
public:
    bool circularArrayLoop(vector<int>& nums) {
        if(nums.size() < 2) return false;
        for(int i = 0; i < nums.size(); ++i) {
            if(circularStartFromIdx(nums, i))
                return true;
        }

        return false;
    }

private:
    bool circularStartFromIdx(vector<int>& nums, int idx) {
        // Find the loop
        int slow = idx, fast = idx;

        do {
            slow = (slow + nums[slow]) % nums.size();
            fast = (fast + nums[fast]) % nums.size();
            fast = (fast + nums[fast]) % nums.size();
        }while(slow != fast);

        // Calculate the length, if length <= 1, return false
        int l = 0;
        do {
            slow = (slow + nums[slow]) % nums.size();
            ++l;
        }while(slow != fast);

        if(l <= 1) return false;

        // Check forward or backward, if two directions, return false
        bool positive = false, negative = false;
        do {
            if(nums[slow] > 0) positive = true;
            else negative = true;

            if(positive & negative) return false;

            slow = (slow + nums[slow]) % nums.size();
        }while(slow != fast);

        return true;
    }
};

不過,上面的解法還是會掛在 [-1,-1,-1]

Trial 3

後來發現,上面的解法會掛在 [-1,-1,-1]是因為我沒有 handle 好往負方向移動的情況,稍微修改一下程式碼就可以過了:

class Solution {
public:
    bool circularArrayLoop(vector<int>& nums) {
        if(nums.size() < 2) return false;
        for(int i = 0; i < nums.size(); ++i) {
            if(circularStartFromIdx(nums, i))
                return true;
        }

        return false;
    }

private:
    bool circularStartFromIdx(vector<int>& nums, int idx) {
        // Find the loop
        int slow = idx, fast = idx;

        do {
            slow = (slow + nums[slow] + nums.size()) % nums.size();
            fast = (fast + nums[fast] + nums.size()) % nums.size();
            fast = (fast + nums[fast] + nums.size()) % nums.size();
        }while(slow != fast);

        // Calculate the length, if length <= 1, return false
        int l = 0;
        do {
            slow = (slow + nums[slow] + nums.size()) % nums.size();
            ++l;
        }while(slow != fast);

        if(l <= 1) return false;

        // Check forward or backward, if two directions, return false
        bool positive = false, negative = false;
        do {
            if(nums[slow] > 0) positive = true;
            else negative = true;

            if(positive & negative) return false;

            slow = (slow + nums[slow] + nums.size()) % nums.size();
        }while(slow != fast);

        return true;
    }
};

可惜效率不是很高: Runtime: 48 ms, faster than 13.61% of C++ online submissions for Circular Array Loop. Memory Usage: 8.5 MB, less than 80.00% of C++ online submissions for Circular Array Loop.

解法一 - Fast & Slow Pointer

using namespace std;

#include <iostream>
#include <vector>

class CircularArrayLoop {
 public:
  static bool loopExists(const vector<int> &arr) {
    for (int i = 0; i < arr.size(); i++) {
      bool isForward = arr[i] >= 0;  // if we are moving forward or not
      int slow = i, fast = i;

      // if slow or fast becomes '-1' this means we can't find cycle for this number
      do {
        slow = findNextIndex(arr, isForward, slow);  // move one step for slow pointer
        fast = findNextIndex(arr, isForward, fast);  // move one step for fast pointer
        if (fast != -1) {
          fast = findNextIndex(arr, isForward, fast);  // move another step for fast pointer
        }
      } while (slow != -1 && fast != -1 && slow != fast);

      if (slow != -1 && slow == fast) {
        return true;
      }
    }

    return false;
  }

 private:
  static int findNextIndex(const vector<int> &arr, bool isForward, int currentIndex) {
    bool direction = arr[currentIndex] >= 0;
    if (isForward != direction) {
      return -1;  // change in direction, return -1
    }

    // wrap around for negative numbers
    int nextIndex = (currentIndex + arr[currentIndex] + arr.size()) % arr.size();

    // one element cycle, return -1
    if (nextIndex == currentIndex) {
      nextIndex = -1;
    }

    return nextIndex;
  }
};

int main(int argc, char *argv[]) {
  cout << CircularArrayLoop::loopExists(vector<int>{1, 2, -1, 2, 2}) << endl;
  cout << CircularArrayLoop::loopExists(vector<int>{2, 2, -1, 2}) << endl;
  cout << CircularArrayLoop::loopExists(vector<int>{2, 1, -1, -2}) << endl;
}

Last updated