Monthly Archives: March 2017

LeetCode Minimum Moves to Equal Array Elements II

LeetCode Minimum Moves to Equal Array Elements II Given a non-empty integer array, find the minimum number of moves required to make all array elements equal, where a move is incrementing a selected element by 1 or decrementing a selected element by 1. You may assume the array’s length is at most 10,000. Example:

Input:
[1,2,3]
Output:
2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3]  =>  [2,2,3]  =>  [2,2,2]

LeetCode Minimum Moves to Equal Array Elements的改编题。这次每次只能改变一个数,让其增大1或者减小1,问最小需要多少次操作能使所有数字相等。 其实看样例就能猜到,最终统一的那个数是原数组中的中位数。这就好办了,对原数组排个序,然后累加所有元素和中位数的绝对值就可以了。 代码如下: [cpp] class Solution { public: int minMoves2(vector<int>& nums) { sort(nums.begin(), nums.end()); int ans = 0, mid = nums[nums.size() / 2]; for (const int& i : nums)ans += abs(i – mid); return ans; } }; [/cpp] 本代码提交AC,用时22MS。 排好序之后还有另一种方法求操作数,比如排好序是1,3,5,7,9,最终所有数都要变成5。之前的做法是所有数和5作差求绝对值加和,现在可以这样做,1到5需要(5-1)次操作,9变成5需要(9-5)次操作,累加就是(5-1)+(9-5)=(9-1),所以我们取排序之后的首位元素,互相作差即可。这就看起来和中位数没关系了。 代码如下: [cpp] class Solution { public: int minMoves2(vector<int>& nums) { sort(nums.begin(), nums.end()); int ans = 0, i = 0, j = nums.size() – 1; while (i < j) { ans += nums[j–] – nums[i++]; } return ans; } }; [/cpp] 本代码提交AC,用时19MS。 既然是要求中位数,其实不用对数组排序都可以做到,就是之前的求第k大数LeetCode Kth Largest Element in an Array,直接借用那个函数即可。STL也有类似的函数nth_element。 [cpp] class Solution { private: int helper(vector<int>& nums, int left, int right, int k) { if (left == right)return nums[left]; int pivot = nums[left]; int l = left, r = right; while (l < r) { while (l < r&&nums[r] <= pivot)–r; if (l >= r)break; nums[l] = nums[r]; while (l < r&&nums[l] >= pivot)++l; if (l >= r)break; nums[r] = nums[l]; } nums[l] = pivot; if (l + 1 == k)return pivot; if (k < l + 1)return helper(nums, left, l – 1, k); else return helper(nums, l + 1, right, k); } public: int minMoves2(vector<int>& nums) { //int ans = 0, mid = helper(nums, 0, nums.size() – 1, nums.size() / 2 + 1); nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end()); int ans = 0, mid = nums[nums.size() / 2]; for (const int& i : nums)ans += abs(i – mid); return ans; } }; [/cpp] 本代码提交AC,用时13MS。]]>

LeetCode Minimum Moves to Equal Array Elements

LeetCode Minimum Moves to Equal Array Elements Given a non-empty integer array of size n, find the minimum number of moves required to make all array elements equal, where a move is incrementing n – 1 elements by 1. Example:

Input:
[1,2,3]
Output:
3
Explanation:
Only three moves are needed (remember each move increments two elements):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

给定一个长度为n数组,每次操作是把其中n-1个数加1,问需要多少次操作才能使数组中的所有元素都相等。 很有意思的数学题。常规思路是,每次找出数组中的最大数,然后对剩下的n-1个数加1,如此循环直到所有元素相等。但是这种解法每次操作都需要O(n)的复杂度,肯定会TLE。 另一个思路,对除最大数之外的所有数加1,相当于其他数不变,把最大数减1。所以可以先找到数组中的最小数,然后累加数组中各元素与最小值之差即可。 代码如下: [cpp] class Solution { public: int minMoves(vector<int>& nums) { int m = INT_MAX, ans = 0; for (const int& i : nums)m = min(m, i); for (const int& i : nums)ans += i – m; return ans; } }; [/cpp] 本代码提交AC,用时56MS。]]>

LeetCode Number of Boomerangs

LeetCode Number of Boomerangs Given n points in the plane that are all pairwise distinct, a “boomerang” is a tuple of points (i, j, k) such that the distance between iand j equals the distance between i and k (the order of the tuple matters). Find the number of boomerangs. You may assume that n will be at most 500 and coordinates of points are all in the range [-10000, 10000] (inclusive). Example:

Input:
[[0,0],[1,0],[2,0]]
Output:
2
Explanation:
The two boomerangs are [[1,0],[0,0],[2,0]] and [[1,0],[2,0],[0,0]]

给定一堆点集,问回飞镖的个数。一个回飞镖是一个三点集(i,j,k),且满足i到j和k的距离相等。 如果和i距离相等的点有n个,则这样的三点集有$$A_n^2=n(n-1)$$,也就是从n个点中拿两个点做排列。所以问题就转换为对每个点,都求其他所有点和该点的距离,求到距离相等的点的个数n,然后代入公式计算。 代码如下: [cpp] class Solution { public: int numberOfBoomerangs(vector<pair<int, int>>& points) { int ans = 0; for (int i = 0; i < points.size(); ++i) { unordered_map<int, int> dist_cnt; for (int j = 0; j < points.size(); ++j) { int xdiff = points[i].first – points[j].first; int ydiff = points[i].second – points[j].second; ++dist_cnt[xdiff*xdiff + ydiff*ydiff]; } for (auto it = dist_cnt.begin(); it != dist_cnt.end(); ++it)ans += it->second*(it->second – 1); } return ans; } }; [/cpp] 本代码提交AC,用时369MS。 因为题中说到所有点都是不相同的,所以第7行没必要限制j!=i,即使j==i,算出来的距离是0,dist_cnt[0]=1,也就是只有点x一个点和自己的距离是0。到第12行计算排列数时,n(n-1)=0,所以没关系。]]>

LeetCode Find All Anagrams in a String

LeetCode Find All Anagrams in a String Given a string s and a non-empty string p, find all the start indices of p‘s anagrams in s. Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100. The order of output does not matter. Example 1:

Input:
s: "cbaebabacd" p: "abc"
Output:
[0, 6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input:
s: "abab" p: "ab"
Output:
[0, 1, 2]
Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab".
The substring with start index = 1 is "ba", which is an anagram of "ab".
The substring with start index = 2 is "ab", which is an anagram of "ab".

给定两个字符串s和p,要从s中找出所有和p是变位词的子串的起始位置。 判断两个字符串是否为变位词,可以用Hash的方法,在LeetCode Group Anagrams中已经介绍过了。 本题的思路也很简单,遍历s,每次从左端删掉一个字符,加入右端的一个字符,判断s和p的Hash表是否相等,相等就说明是一个变位词。 代码如下: [cpp] class Solution { public: vector<int> findAnagrams(string s, string p) { int slen = s.size(), plen = p.size(); if (slen < plen)return vector<int>(); vector<int> ans; vector<int> hash1(26, 0), hash2(26, 0); for (int i = 0; i < plen; ++i) { ++hash1[s[i] – ‘a’]; ++hash2[p[i] – ‘a’]; } if (hash1 == hash2)ans.push_back(0); for (int i = plen; i < slen; ++i) { –hash1[s[i – plen] – ‘a’]; ++hash1[s[i] – ‘a’]; if (hash1 == hash2)ans.push_back(i – plen + 1); } return ans; } }; [/cpp] 本代码提交AC,用时33MS。]]>

LeetCode Kth Largest Element in an Array

215. Kth Largest Element in an Array215. Kth Largest Element in an Array

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1:

Input: [3,2,1,5,6,4] and k = 2
Output: 5

Example 2:

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.215. Kth Largest Element in an Array


本题要求一个未排序数组中第k大的数。
解法1,直接从大到小排序,然后取第k个数,时间复杂度O(nlgn)。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k)
    {
        sort(nums.begin(), nums.end(), std::greater<int>());
        return nums[k – 1];
    }
};

本代码提交AC,用时16MS。
解法2,借助快排的思路,每次选择一个枢纽pivot,把区间[left,right]划分为比pivot大和小的两个部分,然后就能确定pivot的最终位置,如果其下标正好是k-1,则说明pivot就是第k大的数。否则可以判断第k大的数在左半边还是右半边,然后递归在其中一半查找第k大的数。时间复杂度可以由T(n)=T(n/2)+O(n)解出是O(n),注意我们只需要在其中一半递归,所以是加一个T(n/2)。
代码如下:

class Solution {
private:
    int helper(vector<int>& nums, int left, int right, int k)
    {
        if (left == right)
            return nums[left];
        int pivot = nums[left];
        int l = left, r = right;
        while (l < r) {
            while (l < r && nums[r] <= pivot)
                –r;
            if (l >= r)
                break;
            nums[l] = nums[r];
            while (l < r && nums[l] >= pivot)
                ++l;
            if (l >= r)
                break;
            nums[r] = nums[l];
        }
        nums[l] = pivot;
        if (l + 1 == k)
            return pivot;
        if (k < l + 1)
            return helper(nums, left, l – 1, k);
        else
            return helper(nums, l + 1, right, k);
    }
public:
    int findKthLargest(vector<int>& nums, int k) { return helper(nums, 0, nums.size() – 1, k); }
};

本代码提交AC,用时39MS,居然比直接排序还慢。。。
解法3,使用堆排序。对原数组建一个最大堆,然后不断的把前k-1个堆顶弹出,下一个堆顶元素就是第k大的元素。建堆时间为O(n),维护堆的性质需要O(lgn)时间,所以总时间复杂度为O(klgn+n)。
代码如下:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k)
    {
        priority_queue<int> pq(nums.begin(), nums.end());
        for (int i = 0; i < k – 1; ++i)
            pq.pop();
        return pq.top();
    }
};

本代码提交AC,用时9MS,是最快的。
二刷。还是使用快排划分的方法,但是这次把partition的过程单独抽出来了,逻辑更清晰,代码如下:

class Solution {
private:
    int partition(vector<int>& nums, int start, int end)
    {
        if (start >= end)
            return start;
        int i = start, j = end, pivot = nums[start];
        while (i < j) {
            while (i < j && nums[j] <= pivot)
                –j; // 注意符号,从大到小排序
            if (i < j) {
                nums[i] = nums[j];
                ++i;
            }
            while (i < j && nums[i] > pivot)
                ++i; // 注意符号,从大到小排序
            if (i < j) {
                nums[j] = nums[i];
                –j;
            }
        }
        nums[i] = pivot;
        return i;
    }
public:
    int findKthLargest(vector<int>& nums, int k)
    {
        int start = 0, end = nums.size() – 1;
        while (true) {
            int p = partition(nums, start, end);
            if (p + 1 == k)
                return nums[p];
            else if (p + 1 < k)
                start = p + 1;
            else
                end = p – 1;
        }
        return -1;
    }
};

本代码提交AC,用时23MS。

三刷。更简洁不易出错的快排划分方法:

class Solution {
private:
	int FindK(vector<int>& nums, int left, int right, int k) {
		int pivot = nums[right];
		int next_idx = left;
		for (int i = left; i <= right; ++i) {
			if (nums[i] > pivot) {
				swap(nums[i], nums[next_idx++]);
			}
		}
		swap(nums[right], nums[next_idx]);
		int rank = next_idx + 1 - left;
		if (rank == k)return pivot;
		else if (k < rank)return FindK(nums, left, next_idx - 1, k);
		else return FindK(nums, next_idx + 1, right, k - rank);
	}
public:
	int findKthLargest(vector<int>& nums, int k) {
		return FindK(nums, 0, nums.size() - 1, k);
	}
};

本代码提交AC,用时212MS。

LeetCode Bitwise AND of Numbers Range

201. Bitwise AND of Numbers Range

Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.

Example 1:

Input: [5,7]
Output: 4

Example 2:

Input: [0,1]
Output: 0

求把从m~n的所有整数相与的结果。
暴力方法就是从m到n遍历一遍,把所有数都相与一下。但是TLE。
这题明显是个数学题或者找规律题。网上的解法大多数是这样的,把m~n的所有数相与的结果等于m和n这两个数的二进制的最长公共前缀。比如题目中的[5,7],5和7的二进制分别为101和111,最长公共前缀就是100=4,后两位不一样也要补0。再比如[26,30],26和30的二进制分别为11010和11110,最长公共前缀为11000=24。
知道这个规律就好办了,因为m和n都是正数,不断同时把m和n往右移,直到他们相等,最后再把m往左移回去就是最终结果。代码如下:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n)
    {
        int offset = 0;
        while (m != n) {
            m >>= 1;
            n >>= 1;
            ++offset;
        }
        return m << offset;
    }
};

本代码提交AC,用时69MS。

二刷。看下面的图,m和n最长公共前缀后面的二进制位,在[m,n]范围内都在不停的变化,也就是有0也有1,所以全与之后肯定都是0,只有公共前缀的1相与不会变0,所以要找公共前缀。

LeetCode Number of Islands

200. Number of Islands

Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

Example 1:

Input:
11110
11010
11000
00000

Output: 1

Example 2:

Input:
11000
11000
00100
00011

Output: 3

给定一个二维数组,标’1’表示陆地,标’0’表示水。问这个网格中共有多少个岛屿。一个岛屿就是若干个联通的’1’。 简单题,对所有标’1’的网格进行DFS或BFS,把所有联通的’1’都标记一下。下次遇到一个没标记的’1’就代表一个新的岛屿的出现。 完整代码如下:

class Solution {
private:
    void dfs(vector<vector<char> >& grid, vector<vector<int> >& mark, int i, int j, const int& m, const int& n)
    {
        mark[i][j] = 1;
        if (i – 1 >= 0 && grid[i – 1][j] == ‘1’ && mark[i – 1][j] == 0)
            dfs(grid, mark, i – 1, j, m, n);
        if (i + 1 < m && grid[i + 1][j] == ‘1’ && mark[i + 1][j] == 0)
            dfs(grid, mark, i + 1, j, m, n);
        if (j – 1 >= 0 && grid[i][j – 1] == ‘1’ && mark[i][j – 1] == 0)
            dfs(grid, mark, i, j – 1, m, n);
        if (j + 1 < n && grid[i][j + 1] == ‘1’ && mark[i][j + 1] == 0)
            dfs(grid, mark, i, j + 1, m, n);
    }
public:
    int numIslands(vector<vector<char> >& grid)
    {
        int m = grid.size(), n = 0;
        if (m != 0)
            n = grid[0].size();
        if (m == 0 || n == 0)
            return 0;
        vector<vector<int> > mark(m, vector<int>(n, 0));
        int ans = 0;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == ‘1’ && mark[i][j] == 0) {
                    ++ans;
                    dfs(grid, mark, i, j, m, n);
                }
            }
        }
        return ans;
    }
};

本代码提交AC,用时9MS。

LeetCode Repeated DNA Sequences

187. Repeated DNA Sequences

All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: “ACGAATTCCG”. When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.

Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.

Example:

Input: s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT"

Output: ["AAAAACCCCC", "CCCCCAAAAA"]

题意:给定一个DNA序列,问有哪些长度为10的子串出现过至少两次。 解法:遍历字符串,用Hash表记录所有长度为10的子串的出现频率,如果频率等于2,则把该子串加入到结果数组中。时间复杂度为O(n),空间复杂度为Hash表占用的空间。 完整代码如下:

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s)
    {
        vector<string> ans;
        unordered_map<string, int> hash;
        for (size_t i = 0; i + 10 <= s.size(); ++i) {
            string seq = s.substr(i, 10);
            ++hash[seq];
            if (hash[seq] == 2)
                ans.push_back(seq);
        }
        return ans;
    }
};

本代码提交AC,用时73MS。
优化思路:
因为碱基只有4个:A,T,G,C,所以可以用两个bit表示所有碱基,子串的长度为10,所以可以用20bits表示一个子串,也就是用一个int就可以表示一个子串了。所以我们在将长度为10的子串插入Hash表时,可以先将其编码成一个int。这样Hash表的key就变成一个int了,Hash存储空间应该会更小,而且int也更利于Hash的查找。
完整代码如下:

class Solution {
private:
    unsigned int encode(const string& s)
    {
        unsigned int code = 0;
        for (size_t i = 0; i < s.size(); ++i) {
            code <<= 2;
            switch (s[i]) {
            case ‘A’:
                code += 0;
                break;
            case ‘T’:
                code += 1;
                break;
            case ‘C’:
                code += 2;
                break;
            case ‘G’:
                code += 3;
                break;
            }
        }
        return code;
    }
public:
    vector<string> findRepeatedDnaSequences(string s)
    {
        vector<string> ans;
        unordered_map<unsigned int, int> hash;
        for (size_t i = 0; i + 10 <= s.size(); ++i) {
            string seq = s.substr(i, 10);
            unsigned int code = encode(seq);
            ++hash[code];
            if (hash[code] == 2)
                ans.push_back(seq);
        }
        return ans;
    }
};

本代码提交AC,用时59MS,快了一点。

LeetCode Largest Number

179. Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.

Example 1:

Input: [10,2]
Output: "210"

Example 2:

Input: [3,30,34,5,9]
Output: "9534330"

Note: The result may be very large, so you need to return a string instead of an integer.


给定一个数组,要把数组中所有的数拼成一个长的数,问能够拼成的最大的数是多少,要求返回这个最大数的字符串形式。

要想长数越大,则数组中“越大的数”应该排在前面,这里的“大”是指字典序,比如9就比34大,所以9应该在字符串中排前面。所以大的思路是先把数字数组转换为对应的字符串数组,然后按字典序对字符串数组排序,最后按先后顺序拼接起来。

还有一个问题是,遇到30和34时,应该把34排在30的前面,即3430>3034,这符合字典序,没什么问题。

另一个问题是,遇到一个数是另一个数的前缀的情况,应该怎么排序呢,比如34和349时,应该是349排在34的前面,因为34934>34349,这也符合字典序。但是,如果是34和341,正确的排序应该是34排在341的前面,因为34341>34134,此时就不符合字典的降序了。所以需要自定义一个对字符串的排序算法,此算法要对字符串s1和s2进行比较,方法是判断s1+s2和s2+s1的字典序,因为这就是这两个字符串按不同顺序拼接之后的大小。

最后一个问题,如果遇到数组是[0,0],即两个0时,能拼成的最大数是0,但是如果先转换成字符数组之后,拼成的数就是00了。所以在最后,我们判断一下开头的字符是否为’0’,如果是,说明这个数就是0了,不管后面是否还有多余的字符’0’,我们都只返回”0″。如果开头的字符不是’0’,则多个’0’是有效的,比如30和300是不同的两个数。

完整代码如下:

bool comp(const string& s1, const string& s2)
{
    string tmp1 = s1 + s2, tmp2 = s2 + s1;
    return tmp1 > tmp2;
}
class Solution {
public:
    string largestNumber(vector<int>& nums)
    {
        vector<string> snums;
        for (size_t i = 0; i < nums.size(); ++i)
            snums.push_back(to_string(nums[i]));
        sort(snums.begin(), snums.end(), comp);
        string ans = "";
        for (size_t i = 0; i < snums.size(); ++i)
            ans += snums[i];
        if (!ans.empty() && ans[0] == ‘0’)
            return "0";
        return ans;
    }
};

本代码提交AC,用时6MS。

代码中注意一点,自定义的比较函数不能是类的成员函数,要不然会报错“非标准语法;请使用 “&” 来创建指向成员的指针”,这个错误提示很奇怪。后来才知道比较函数必须定义成全局函数或者静态函数,因为sort自己就是全局或静态函数,无法调用成员函数

LeetCode Fraction to Recurring Decimal

166. Fraction to Recurring Decimal

Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.

If the fractional part is repeating, enclose the repeating part in parentheses.

Example 1:

Input: numerator = 1, denominator = 2
Output: "0.5"

Example 2:

Input: numerator = 2, denominator = 1
Output: "2"

Example 3:

Input: numerator = 2, denominator = 3
Output: "0.(6)"

本题要把两数相除的结果转换为小数字符串,对于无限循环小数,把循环部分用括号括起来。 参考欣欣的做法。 首先判断一下符号位,如果异号则添加负号,然后把两数都转换为正数,注意因为int的负数个数比正数个数多一个-2147483648,abs(-2147483648)=-2147483648还是负数,因为int最大的正数是2147483647,导致转换为正数时溢出成-2147483648。所以需要先把分子分母转换为long long再取绝对值。

整数部分就是分子除以分母。如果没有余数,就整除了,直接返回结果;否则添加小数点,开始处理小数部分。小数部分判断是否有无限循环小数周期的方法是,用一个map保留每次除法的余数,以及对应的商在结果字符串中的位置,如果以后某次的余数在这个map中,就表明小数部分要开始循环了,通过map找到循环的起始位置,添加左括号,并在结果字符串末尾添加有括号就结束了。比如4/9,用长除法,第一次上0,添加小数点,余数为4。余数乘10再除以9,即40/9=4,余数还是4,因为之前有出现过4的余数,所以开始循环了。 有些除法能除尽,除尽的标志就是余数为0,所以也需要在循环的时候判断余数是否为0。 需要注意的一点是,不能对商建立hash表,比如某个小数是3.(5883),循环周期是5883,如果对商建立hash,则出现第二个8时,会误以为开始循环周期了,导致结果3.5(8),而正确的循环周期应该是5883。正确的做法是对余数建立hash表。 完整代码如下:

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator)
    {
        if (numerator == 0)
            return "0";
        string ans = "";
        if ((numerator < 0) ^ (denominator < 0))
            ans = "-";
        long long num = llabs((long long)numerator), denom = llabs((long long)denominator);
        ans += to_string(num / denom);
        if (num % denom == 0)
            return ans;
        ans += ".";
        unordered_map<int, int> hash;
        long long reminder = num % denom;
        while (hash.find(reminder) == hash.end()) {
            hash[reminder] = ans.size();
            reminder *= 10;
            ans += to_string(reminder / denom);
            reminder %= denom;
            if (reminder == 0)
                return ans;
        }
        ans.insert(hash[reminder], "(");
        ans += ")";
        return ans;
    }
};

本代码提交AC,用时3MS。

二刷。相同思路:

class Solution {
public:
	string fractionToDecimal(int num, int denom) {

		long long numerator = num, denominator = denom;

		if (numerator == 0)return "0";
		if (denominator == 1)return to_string(numerator);
		if (denominator == -1)return to_string(-numerator);

		bool pos = true;
		if (numerator < 0) {
			numerator = -numerator;
			pos = !pos;
		}
		if (denominator < 0) {
			denominator = -denominator;
			pos = !pos;
		}

		unordered_map<int, int> hash;
		hash[numerator] = 0;
		vector<int> ans;
		
		int rep_start = -1;
		while (true) {
			int div = numerator / denominator;
			ans.push_back(div);
			numerator -= div * denominator;
			if (numerator == 0)break;
			numerator *= 10;
			if (hash.find(numerator) != hash.end()) {
				rep_start = hash[numerator];
				break;
			}
			else {
				hash[numerator] = ans.size();
			}
		}

		string frac = pos ? "" : "-";
		if (ans.size() == 1) {
			return frac + to_string(ans[0]);
		}
		frac += (to_string(ans[0]) + ".");
		for (int i = 1; i < ans.size(); ++i) {
			if (i == rep_start)frac += "(";
			frac += to_string(ans[i]);
		}
		if (rep_start >= 0)frac += ")";
		return frac;
	}
};

本代码提交AC,用时4MS。