nums = [0, 0, 1, 1, 1, 0, 1, 1] 이면, 최대 길이는 6이다.1 <= nums.length <= 10^5풀기 전
k라고 하고 모든 subarray를 고려한다고 했을 때, 모든 subarray 개수는 k(subarray 길이가 1인 경우) + k-1(subarray 길이가 2인 경우) + k-2(subarray 길이가 3인 경우) + ... + 1 = k(k+1)/2이다. k의 최대값이 10^5이니까 최대 50억 정도의 값이 나온다. 그런데 subarray가 홀수인 경우는 신경 안 써도 되니까 절반 정도인 25억으로 추정할 수 있다. 보통 1억을 1초로 잡는데 25초면 너무 오래 걸렸다. 그런데 다른 방법이 생각이 안 나서 일단 구현해봤다.코드
class Solution {
public:
// 탐색하기 시작할 subarray 크기를 정하는 함수이다.
// 0이나 1이 하나밖에 없는데 subarray 크기를 크게 잡아봤자 소용이 없으므로,
// 0과 1의 개수 중 작은 값의 2를 곱한 값을 반환한다.
int getWindowSize(vector<int> nums) {
int zeroNum = 0;
int oneNum = 0;
for (auto& num : nums) {
if (num == 0)
zeroNum++;
else
oneNum++;
}
return min(zeroNum, oneNum) * 2;
}
int findMaxLength(vector<int>& nums) {
// 탐색을 시작할 subarray 크기를 받아온다.
// 해당 값부터 시작하여 2씩 크기를 줄여나간다.
int windowSize = getWindowSize(nums);
// 현재 subarray의 값을 모두 더한다.
int initSum = 0;
for (int i=0; i<windowSize; i++)
initSum += nums[i];
// subarray 크기를 2씩 줄이면서 탐색 시작한다.
for (int size=windowSize; size >= 2; size -= 2) {
// 종료 조건 체크
// nums는 0과 1로만 이루어져 있으므로, 합의 2배가 subarray 크기와 같으면 종료한다.
if (initSum * 2 == size)
return size;
int sum = initSum;
// subarray를 옆으로 옮기면서 종료 조건을 체크한다.
for (int i=1; i+size <= nums.size(); i++) {
sum -= nums[i-1]; // subarray에서 벗어난 값을 빼준다.
sum += nums[i+size-1]; // subarray에 추가된 값을 더해준다.
// 종료 조건 체크
if (sum * 2 == size)
return size;
}
// subarray 크기를 2 줄일거기 때문에, 맨 마지막에 있는 두 값을 빼준다.
initSum -= (nums[size-1] + nums[size-2]);
}
return 0;
}
};
푼 후
풀기 전
코드
class Solution {
public:
int findMaxLength(vector<int>& nums) {
// sum을 키로 갖고, nums의 idx를 값으로 갖는 unordered map을 만든다.
unordered_map<int, int> sum_idx_map;
sum_idx_map[0] = -1; // sum이 0인 경우는 엣지케이스이므로 -1을 직접 넣어준다.
int max_length = 0;
int sum = 0;
// nums를 탐색한다.
for (int i=0; i<nums.size(); i++) {
// 값이 0이면 sum에 -1 하고, 1이면 +1 한다.
if (nums[i] == 0)
sum--;
else // num == 1
sum++;
// sum이 map에 없으면 {sum:idx}를 추가해준다.
if (sum_idx_map.find(sum) == sum_idx_map.end()) {
sum_idx_map[sum] = i;
} else {
// sum이 map에 있다는 건 이전에 같은 sum이 나온 적이 있다는 거다.
// 즉, 이전에 sum이 나온 이후로 오르락 내리락 하다가 다시 돌아왔다는 거다.
// 현재 idx와 이전의 idx 차이를 통해 subarray 크기를 구할 수 있다.
int sub_length = i - sum_idx_map[sum];
max_length = max(sub_length, max_length);
}
}
return max_length;
}
};
{sum: idx}로 추가해준다.nums=[0, 1, 1, 1, 0]일 때 아래와 같은 과정을 거친다.idx = 0idx = 1현재 위치 - 이전 위치 = 1 - (-1) = 2idx = 2idx = 3idx = 4현재 위치 - 이전 위치 = 4 - 2 = 2푼 후