LintCode 264: Counting Universal Subarrays (数组好题)

264. Counting Universal Subarrays

You will be given an array comprised of '2's or '4's. A subarray (A subarray is a group of contiguous elements in an array and cannot be empty) of such an array is called " universal" if it matches the following conditions:

  1. The 2's and 4's are grouped consecutively (e.g., [4, 2],[2, 4],[4, 4, 2, 2],[2, 2, 4, 4],[4, 4, 4, 2, 2, 2], etc.).
  2. The number of 4's in the subarray is equal to the number of 2's in the subarray.
  3. Subarrays with the same element but different positions are treated differently. For example, there are two [4, 2] subarrays in array[4, 2, 4, 2].

You need to return an integer value, the number of "universal" subarrays in a given array.

Example

Sample 1:
Input sample: array = [4, 4, 2, 2, 4, 2]
Output sample: 4
Sample explanation: The 4 subarrays that match these two criteria are: [4, 4, 2, 2],[4,2],[2,4],[4,2]. Note that there are two subarrays [4,2], in indexes 1-2 and 4-5, respectively.

Sample 2:
Input sample: array = [4, 4]
Output sample: 0
Sample explanation: the given array does not have 2, certainly cannot satisfy the condition two, so the result is 0.

Notice

1 ≤ |array| ≤ 10^5
array[i] ∈ (2, 4)

Input test data (one parameter per line)How to understand a testcase?

解法1:
我开始的想法是把数组里面的2和4分别替换成1和-1。这样,求presums只需要看某一段是不是0就可以了。
如果某一段[i..j]的sum是0,注意i到j的数目是偶数个,比如说{4,4,2,2,4,2}, sum(0..3)=0 (注意是把4和2换成了1和-1), 我们可以对其进一步处理,否则就不用管了。如何进一步处理呢?注意{4,4,2,2}会转换成{1,1,-1,-1},那么前半段累加起来的绝对值(因为前半段也可能都是-1)就应该是总数目的一半,即2。这样,可以排除掉{4,2,2,4}的情形,因为这种情况下它会转换成{1,-1,-1,1},前半段累加起来的绝对值是0。

这个算法应该是正确的,不过时间复杂度是O(n^2),还是会超时。

class Solution {
public:
  int subarrays(vector<int> &array) {
     int n = array.size();
     if (n <= 1) return 0;
     
     for (int i = 0; i < n; ++i) {
         if (array[i] == 2) array[i] = -1;
         else array[i] = 1;
     }
     
     vector<long long> presums(n + 1);
     
     for (int i = 1; i <= n; ++i) {
         presums[i] = presums[i - 1] + array[i - 1];
     }

     int result = 0;
     for (int i = 1; i < n; ++i) {
         for (int j = i + 1; j <= n; ++j) {
             if (((j - i) & 0x1) && presums[j] - presums[i - 1] == 0) {
                int mid = (i + j) / 2;
                long long firstHalfSum = presums[mid] - presums[i - 1];

                  if (abs(firstHalfSum * 2) == j - i + 1) {
                    result++;
                }
             }
         }
     }
  }
};

解法2:
参考了牛人的解法。直接将{4,4,2,2,4,2}转换成freq数组,即{2,2,1,2}。那么,结果就是sum of min{freq[i - 1], freq[i]}。非常巧妙!

class Solution {
public:
    /**
     * @param array: An given array.
     * @return: Return the number of "universal" subarrays.
     */
    int subarrays(vector<int> &array) {
         int n = array.size();
         if (n <= 1) return 0;
         int result = 0;
         
         vector<int> freqs;
         int count = 1;
         
         for (int i = 1; i < n; ++i) {
             if (array[i] == array[i - 1]) {
                 count++;
             } else {
                 freqs.push_back(count);
                 count = 1;
             }
         }
         freqs.push_back(count);

         n = freqs.size() - 1;
         for (int i = 0; i < n; ++i) {
             result += min(freqs[i], freqs[i + 1]);
         }
         
         return result; 
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值