題目描述:Given a binary array, find the maximum length of a contiguous subarray with equal number of 0 and 1.
Note: The length of the given binary array will not exceed 50,000.
思路,參考官網,將數組中的 0 全都轉化爲 -1,然後遍歷數組求和sum:如果遍歷到下標a時的sum=K,繼續遍歷到下標b時的sum還是sum=K,(a<b),那麼可以得出(a~b] 的數組滿足要求。即得出結果是 result = b - a;這是這個算法的數學依據。接下來考慮的是當得出sum之後,如何快速的判斷該sum值有沒有出現過,如果出現過,如何快速的找到該sum值對應的下標值?
//方法一,用map結構保存sum值和sum值對應的下標,實現快速判斷sum值是否存在。因爲map的底層實現是紅黑樹數據結構,每次 .find 都需要花費 log(n)的時間。在LeetCode上僅僅擊敗了3.66%的碼友. 運行時間約 200 ms
int findMaxLength(vector<int>& nums) {
int result = 0, sum = 0;
for (int i = 0; i < nums.size(); i++)
if (nums[i] == 0) nums[i] = -1;
map<int, int> m;
m[0] = -1; //這個是必須的初始條件。考慮 0,1 的場景
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (m.find(sum) != m.end()){ //注意,找到了重複的sum,只是更新result,並不對m[sum]做更新
result = max(result, i - m[sum]);
}else{
m[sum] = i; //在相同的幾個sum中,m[sum]總是保存的是最開始的那個下標值
}
}
return result;
}
//方法二,直接用數組保存值。雖然花費了更多的空間,但這個方法測試比方法一快一倍!運行時間約 100 ms
int findMaxLength(vector<int>& nums)
{
int result = 0;
int sum = 0;
//初始化數組
int size = 2*nums.size() + 1;
vector<int> vec;
for(int i=0; i<size; ++i)
{
vec.push_back(-2);
}
vec[0] = -1; //注意vec[0] = -1 必須初始化爲 -1
//遍歷數組,記錄當前的數組和sum,查hash表,
//如果sum對應的值不爲空(-2),那麼sum值出現過,用當前的下標減去sum值對應的下標方式求結果。
//如果sum對應的值爲空(-2),那麼該值沒有出現過,需要保存當前sum的下標值
int sumTmp = 0;
for(int i=0;i<nums.size();++i)
{
if(0==nums[i])
{
sum -= 1;
}else{
sum += 1;
}
//哈希轉換,sum<0時取反,在加上vec的size大小(sum爲負值時用vec[n+1~2n])
if(sum<0){
sumTmp = (nums.size() - sum);
}else{
sumTmp = sum;
}
//assert(sumTmp<size); //證明sumTmp不越界訪問
if(-2 != vec[sumTmp]) //有記錄則更新結果
{
result = max(result, i - vec[sumTmp]);
}else{ //沒有記錄則更新
vec[sumTmp] = i;
}
}
return result;
}
//第三種解法,需要熟悉C++的map實現的數據結構,map底層實現是紅黑樹,有沒有底層實現是hash的map,實現 .find 方法的Q(1)訪問? 答案是 unordered_map,所以選對工具很重要。該方法兼顧時間和空間效率,實現簡單,難以出錯。在LeetCode上擊敗了 93.84% 的碼友。
int findMaxLength(vector<int>& nums) {
int result = 0, sum = 0;
for (int i = 0; i < nums.size(); i++)
if (nums[i] == 0) nums[i] = -1;
unordered_map<int, int> m;
m[0] = -1; //這個是必須的初始條件。考慮 0,1 的場景
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
if (m.find(sum) != m.end()){ //注意,找到了重複的sum,只是更新result,並不對m[sum]做更新
result = max(result, i - m[sum]);
}else{
m[sum] = i; //在相同的幾個sum中,m[sum]總是保存的是sum第一次出現的那個下標值
}
}
return result;
}