[Python3]Three solutions with detailed explanation.
Solution 1: AC. Takes mn * log(mn) calls of Random avgeragely to flip a matrix.\n- Same as all other solutions using set, while see matrix as a vector. Got AC. 
### Solution 1: AC. Takes mn * log(mn) calls of Random avgeragely to flip a matrix.\n- Same as all other solutions using **set**, while see matrix as a vector. **Got AC**. **How many calls of Random avgeragely to flip a matrix?**\n- Say we have a vector of size mn(m * n for matrix). \n- To flip a matrix in total we need 1 + mn/(mn-1) + mn/(mn-2) + ... + mn/1 = mn * (1/1 + 1/2 + 1/3 + ... + 1/mn) = **mn * log(mn)**\n- ref: https://en.wikipedia.org/wiki/Harmonic_number\n\t\n### Solution 2: MLE. Only takes mn calls of Random avgeragely to flip a matrix, but get MLE when m*n is huge\n- Faster solution. **It only takes mn calls** of Random avgeragely to flip a matrix, **but get MLE when m*n is huge**.\n- Code is easy to understand. Here\'s an example:\n- [0, 1, 2, 3, 4 , 5], self.tail = 5. Suppose that we randomly select the index at 2(which is 2), then we need to swap indices at 2 and self.tail. We get,\n- [0, 1, 5, 3, 4 , 2], self.tail = 4. 2 has been selected and dropped.\n\n### Solution 3: AC. Optimized from solution 2\n- By using get_or_default(), optimize space complexity. See the code.\n\n```\nclass Solution:\n\n    def __init__(self, m: int, n: int):\n        self.nums = m * n - 1\n        self.cols = n\n        self.flipped = set()\n        \n\n    def flip(self) -> List[int]:\n        rc = random.randint(0, self.nums)\n        while rc in self.flipped:\n            rc = random.randint(0, self.nums)\n            \n        self.flipped.add(rc)\n        return [rc // self.cols, rc % self.cols]\n    \n\n    def reset(self) -> None:\n        self.flipped = set()\n```\n\n```\nclass Solution:\n\n    def __init__(self, m: int, n: int):\n        self.cols = n\n        self.nums = m * n\n        self.tail = m * n - 1\n        self.indexes = [i for i in range(m * n)]\n        \n    def flip(self) -> List[int]:\n        ind = random.randint(0, self.tail)\n\t\t\n\t\t# swap the selected index with the index at self.indexes[self.tail]\n        rc = self.indexes[ind]\n        self.indexes[ind] = self.indexes[self.tail]\n\t\t# decrease self.tail by one means we drop the candidates flipped.\n        self.tail -= 1\n        \n        return [rc // self.cols, rc % self.cols]\n        \n    def reset(self) -> None:\n        self.indexes = [i for i in range(self.nums)]\n        self.tail = self.nums - 1\n```\n```\nclass Solution:\n\n    def __init__(self, m: int, n: int):\n        self.cols = n\n        self.nums = m * n\n        \n        self.tail = self.nums - 1\n        self.indexes = {}\n        \n\n    def flip(self) -> List[int]:\n        ind = random.randint(0, self.tail)\n        rc = self.indexes.get(ind, ind)\n        self.indexes[ind] = self.indexes.get(self.tail, self.tail)\n        self.tail -= 1\n        \n        return [rc // self.cols, rc % self.cols]\n        \n\n    def reset(self) -> None:\n        self.tail = self.nums - 1\n        self.indexes = {}\n```
['Ordered Set', 'Python3']