相同的測試用例,本地運行72ms,LeetCode上卻TLE,可能有哪些原因?
題目鏈接:Longest Substring Without Repeating Characters
語言是C#,代碼中使用了HashSet,是否可能是Mono的HashSet版本性能太差所導致的?代碼:
public static int LengthOfLongestSubstring(string s)
{
if (s.Length &<= 1) { return s.Length; } int length = 0; for (int i = 0; i &< s.Length; i++) { HashSet&set = new HashSet& ();
for (int j = 0; i + j &< s.Length; j++) { int offset = 0; if ((offset = Add(set, s[i + j])) != -1) { length = length &> j ? length : j;
i += offset;
break;
}
}
}
return length;
}public static int Add(HashSet&
set, char ch)
{
if (!set.Add(ch))
{
for (int i = 0; i &< set.Count; i++) { if (set.ElementAt(i) == ch) { return i + 1; } } } return -1; }測試用例過長(長度3W的字元串)就不放了
本機運行截圖:
首先說結論:不是。因為我給了一個只用一個數組的O(n)的解法,仍然TLE了。下面我貼的是能accept的答案,然後注意如果你把數組的長度從256改成65536,它就TLE了。天知道到底發生了什麼。根據Mono的進展,我只能說leetcode用的可能是三千年前的Mono,從不更新。
通常來講刷leetcode我建議使用C語言,畢竟你是為了去面試,面試通常都是用C語言的,什麼垃圾數據結構都沒有,malloc了之後也不需要free,充分鍛煉打字速度。
而且leetcode計算速度的方法也十分詭異。通一份代碼我不斷地resubmit,可以看見他在90%和40%中間來回跳。
public class Solution {
public int LengthOfLongestSubstring(string s) {
var x = new bool[256];
var result = 0;
var current = 0;
var stringLength = s.Length;
for (int i = 0; i &< stringLength; i++)
{
int code = (int)s[i];
if (x[code])
{
var newCurrent = i;
while ((int)s[newCurrent - 1] != code)
{
newCurrent--;
}
for (int j = current; j &< newCurrent; j++)
{
x[(int)s[j]] = false;
}
current = newCurrent;
}
else
{
var length = i - current + 1;
if (result &< length)
{
result = length;
}
}
x[code] = true;
}
return result;
}
}
順手貼一個可以過的解法,和其它答案一樣需要用一個數組代替HashSet:
public class Solution {
public int LengthOfLongestSubstring(string s) {
var max = 0;
var lastSeen = new int[256];
var lastPairStart = -1;
for (int i = 0; i &< lastSeen.Length; i++) lastSeen[i] = -1;
for (int i = 0; i &< s.Length; i++) {
var c = s[i];
var pairLen = i - lastSeen[c];
var seqLen = i - lastPairStart;
max = Math.Max(max, Math.Min(seqLen, pairLen));
lastPairStart = Math.Max(lastSeen[c], lastPairStart);
lastSeen[c] = i;
}
return max;
}
}
C++我也TLE過。
leetcode TLE
本地測試msvc gcc均debug編譯時TLErelease並關優化(僅開inline)均秒return。鬼知道leetcode上面是什麼奇葩編譯選項用C++寫,動態規劃,順利AC:Runtime: 216 ms.Your runtime beats 20.20% of cppsubmissions.
class Solution {
public:
string longestPalindrome(string s) {
const int len = s.size();
if(len &<= 1) return s;
bool dp[len][len]; //dp[i][j]表示s[i..j]是否是迴文
memset(dp, 0, sizeof(dp));
int resLeft = 0, resRight = 0;
dp[0][0] = true;
for(int i = 1; i &< len; i++)
{
dp[i][i] = true;
dp[i][i-1] = true; //這個初始化容易忽略,當k=2時要用到
}
for(int k = 2; k &<= len; k++) //枚舉子串長度
for(int i = 0; i &<= len-k; i++) //枚舉子串起始位置
{
if(s[i] == s[i+k-1] dp[i+1][i+k-2])
{
dp[i][i+k-1] = true;
if(resRight-resLeft+1 &< k)
{
resLeft = i;
resRight = i+k-1;
}
}
}
return s.substr(resLeft, resRight-resLeft+1);
}
};
可能為了卡你的HashSet故意加了點稀奇古怪的東西減速了吧,可以自己實現一個試試。就像有些OJ沒開優化,STL怎麼用怎麼T,手寫一個相同複雜度的類似數據結構就快得飛起。也可以聽輪子哥說的轉C語言,沒現成可用的數據結構你就會少很多這種困擾,逼你手寫。說回這道題,其實O(n)就行,卡得也不算冤。
public class Solution
{
public int LengthOfLongestSubstring(string s)
{
int[] vis = new int[256];
for (int i = 0; i &< 256; ++i)
{
vis[i] = -1;
}
int p1 = 0, ans = 0, len = s.Length;
for (int p2 = 0; p2 &< len; ++p2)
{
if (vis[s[p2]] != -1)
{
ans = Math.Max(ans, p2 - p1);
for (; p1 &<= vis[s[p2]]; ++p1)
{
vis[s[p1]] = -1;
}
}
vis[s[p2]] = p2;
}
return Math.Max(ans, len - p1);
}
};
我來噴輪子了。一個詞:誤人子弟。(題主居然還信了,真同情)
第一,@vczh給的code由於內層循環方向錯誤(從右往左掃)使得複雜度變為了256*n。第二,題主的(期望)複雜度其實是256*n而不是什麼n^3。輪子說HashSet worst case的結論倒沒錯,不過這裡不是看最壞情況的時候。輪子是在五十步笑百步。(心疼輪子評論區被誤導的朋友們)其他幾位答主@周擎宇和@薛訥訥給出的O(n)做法應該都是挺對的,題主可以參考。(另外,@Bravo Yeung您真的看題了嗎)所以結論是:由於HashSet巨大的常數和複雜度的小問題共同導致超時。推薦閱讀:
※賽碼網是個什麼樣的網站?和杭電OJ有什麼關係?
※如何評價2016年3月22日網易的在線筆試系統及試題?
※VJ爬取別的OJ的題目會不會有侵權行為?為什麼?
※一個好的oj是否應該顯示數據點的得分?
※可不可以在Online Judge(在線評測系統)中加入類似OSU!的PP方案的Rank計算方案?
TAG:C# | OnlineJudge | LeetCode |