Talentd
FleetCode
Make and follow sheets.Sign in

Count Subarrays With Even Odd Ratio II solution and explanation

HardArrayBinary Indexed TreeDivide and ConquerMerge Sort5 min read40.9% acceptanceUpdated 4 Aug 2026
Super Hard💀DSA Question asked by Leetcode in Weekly Contest 513(Q4,4013)DSA with Kumar K · 34:46 · 492 viewsWatch on YouTube
4 more videos on this problem
  1. Super Hard💀DSA Question asked by Leetcode in Weekly Contest 513(Q4,4013)DSA with Kumar K · 34:46 · 492 views
  2. Leetcode 4013 | Count Subarrays With Even Odd Ratio II | PBDS | Leetcode weekly contest 513CodeWithMeGuys · 24:31 · 178 views
  3. LeetCode 4011 & 4013 | Weekly Contest 513 Q2 & Q4 | Count Subarrays With Even Odd Ratio I & II 🤯CodeSprint · 21:12 · 111 views
  4. This Ratio Problem is Secretly Inversion Counting (LC 4013)Manjeet Dhayal · 12:23 · 77 views
  5. 4013. Count Subarrays With Even Odd Ratio II | LeetCode Solution | Fenwick Tree / Merge SortDAILY_WEBDEV · 31:23

The problem

You are given an integer array nums and two integers a and b.

For a subarray, let:

  • x be the number of even elements.
  • y be the number of odd elements.

The ratio of even to odd elements in a subarray is defined as x / y, where ratios are compared by their exact rational values.

A subarray is considered valid if:

  • y > 0, and
  • x / y <= a / b.

Return the number of valid subarrays in nums.

Example 1:

Input: nums = [1,2,1,2], a = 3, b = 2

Output: 7

Explanation:

The following are the valid subarrays:

Subarray Values Even Count Odd Count Ratio
nums[0..0] [1] 0 1 0 / 1
nums[0..1] [1, 2] 1 1 1 / 1
nums[0..2] [1, 2, 1] 1 2 1 / 2
nums[0..3] [1, 2, 1, 2] 2 2 2 / 2
nums[1..2] [2, 1] 1 1 1 / 1
nums[2..2] [1] 0 1 0 / 1
nums[2..3] [1, 2] 1 1 1 / 1

Thus, the number of valid subarrays is 7.

Example 2:

Input: nums = [2,2,1], a = 2, b = 1

Output: 3

Explanation:

The following are the valid subarrays:

Subarray Values Even Count Odd Count Ratio
nums[0..2] [2, 2, 1] 2 1 2 / 1
nums[1..2] [2, 1] 1 1 1 / 1
nums[2..2] [1] 0 1 0 / 1

Thus, the number of valid subarrays is 3.

Example 3:

Input: nums = [2,2,2], a = 1, b = 1

Output: 0

Explanation:

Every subarray contains 0 odd numbers, so no subarray is valid.

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 1 <= a, b <= 109​​​​​​​

Approach overview

Problem Overview: You need to count the number of subarrays in which the ratio of even to odd numbers satisfies a given condition.

Approach 1: Brute Force (O(n^2))

Iterate through all possible subarrays and count the even and odd numbers in each. Check if the ratio meets the condition. This approach is straightforward but inefficient for large arrays.

Approach 2: Prefix Sum with Hash Map (O(n))

Use a prefix sum array to store cumulative counts of even and odd numbers. Employ a hash map to store the frequency of specific ratios. This allows you to efficiently count valid subarrays in linear time. This is the optimal approach for large datasets.

Recommended for interviews: Interviewers expect you to discuss the brute force approach to show understanding, but the optimal solution using prefix sum and hash map demonstrates advanced problem-solving skills.

Solution

For a subarray, let x be the number of even elements and y be the number of odd elements. The problem requires y > 0 and \frac{x}{y} \le \frac{a}{b}. Since b > 0 and y > 0, the inequality is equivalent to a cdot y - b cdot x \ge 0.

When y = 0, since the subarray is non-empty, we must have x > 0. In this case, a cdot y - b cdot x = -b cdot x < 0, so the inequality does not hold. Therefore, the two conditions in the problem can be merged into a single one: a cdot y - b cdot x \ge 0.

We treat the odd numbers in nums as a and the even numbers as -b, resulting in an array arr. The original problem is then equivalent to counting the number of non-empty contiguous subarrays of arr whose element sum is at least 0.

Let s be the prefix sum array of arr. The element sum of the subarray [L, R - 1] equals s[R] - s[L], so the problem is further transformed into: how many index pairs (L, R) satisfy 0 \le L < R \le n and s[R] - s[L] \ge 0, i.e., s[L] \le s[R]?

We enumerate R and need to quickly count the number of indices L to the left of R that satisfy s[L] \le s[R]. This can be maintained with a Binary Indexed Tree: we first discretize all values in s (sort and deduplicate), then traverse s from left to right. For each value v = s[R], we query the number of inserted elements not greater than v from the Binary Indexed Tree and add it to the answer, then insert v into the tree.

The time complexity is O(n times log n), and the space complexity is O(n), where n is the length of the array nums.

class BinaryIndexedTree:
    __slots__ = "n", "c"

    def __init__(self, n: int):
        self.n = n
        self.c = [0] * (n + 1)

    def update(self, x: int, delta: int) -> None:
        while x <= self.n:
            self.c[x] += delta
            x += x & -x

    def query(self, x: int) -> int:
        s = 0
        while x:
            s += self.c[x]
            x -= x & -x
        return s


class Solution:
    def countRatioSubarrays(self, nums: list[int], a: int, b: int) -> int:
        n = len(nums)
        s = [0] * (n + 1)
        for i, x in enumerate(nums):
            s[i + 1] = s[i] + (a if x % 2 else -b)

        st = sorted(set(s))
        bit = BinaryIndexedTree(len(st) + 1)
        ans = 0
        for v in s:
            x = bisect_left(st, v) + 1
            ans += bit.query(x)
            bit.update(x, 1)
        return ans
class BinaryIndexedTree {
    private final int n;
    private final int[] c;

    public BinaryIndexedTree(int n) {
        this.n = n;
        this.c = new int[n + 1];
    }

    public void update(int x, int delta) {
        while (x <= n) {
            c[x] += delta;
            x += x & -x;
        }
    }

    public int query(int x) {
        int s = 0;
        while (x > 0) {
            s += c[x];
            x -= x & -x;
        }
        return s;
    }
}

class Solution {
    public long countRatioSubarrays(int[] nums, int a, int b) {
        int n = nums.length;

        long[] s = new long[n + 1];
        for (int i = 0; i < n; i++) {
            s[i + 1] = s[i] + (nums[i] % 2 == 1 ? a : -b);
        }

        long[] st = s.clone();
        Arrays.sort(st);

        int m = 0;
        for (long x : st) {
            if (m == 0 || st[m - 1] != x) {
                st[m++] = x;
            }
        }

        BinaryIndexedTree bit = new BinaryIndexedTree(m + 1);

        long ans = 0;

        for (long v : s) {
            int x = Arrays.binarySearch(st, 0, m, v) + 1;
            ans += bit.query(x);
            bit.update(x, 1);
        }

        return ans;
    }
}
class BinaryIndexedTree {
    int n;
    vector<int> c;

public:
    BinaryIndexedTree(int n)
        : n(n)
        , c(n + 1) {}

    void update(int x, int delta) {
        while (x <= n) {
            c[x] += delta;
            x += x & -x;
        }
    }

    int query(int x) {
        int s = 0;
        while (x > 0) {
            s += c[x];
            x -= x & -x;
        }
        return s;
    }
};

class Solution {
public:
    long long countRatioSubarrays(vector<int>& nums, int a, int b) {
        int n = nums.size();

        vector<long long> s(n + 1);
        for (int i = 0; i < n; i++) {
            s[i + 1] = s[i] + (nums[i] % 2 ? a : -b);
        }

        vector<long long> st = s;
        sort(st.begin(), st.end());
        st.erase(unique(st.begin(), st.end()), st.end());

        BinaryIndexedTree bit(st.size() + 1);

        long long ans = 0;

        for (long long v : s) {
            int x = lower_bound(st.begin(), st.end(), v) - st.begin() + 1;
            ans += bit.query(x);
            bit.update(x, 1);
        }

        return ans;
    }
};
class BinaryIndexedTree {
    private n: number;
    private c: number[];

    constructor(n: number) {
        this.n = n;
        this.c = new Array(n + 1).fill(0);
    }

    update(x: number, delta: number): void {
        while (x <= this.n) {
            this.c[x] += delta;
            x += x & -x;
        }
    }

    query(x: number): number {
        let sum = 0;
        while (x > 0) {
            sum += this.c[x];
            x -= x & -x;
        }
        return sum;
    }
}

function countRatioSubarrays(nums: number[], a: number, b: number): number {
    const n = nums.length;

    const s = new Array<number>(n + 1).fill(0);

    for (let i = 0; i < n; i++) {
        s[i + 1] = s[i] + (nums[i] % 2 === 1 ? a : -b);
    }

    const st = [...s].sort((x, y) => x - y);

    const uniq: number[] = [];
    for (const x of st) {
        if (uniq.length === 0 || uniq[uniq.length - 1] !== x) {
            uniq.push(x);
        }
    }

    const bit = new BinaryIndexedTree(uniq.length + 1);

    let ans = 0;

    for (const v of s) {
        const x = _.sortedIndex(uniq, v) + 1;

        ans += bit.query(x);
        bit.update(x, 1);
    }

    return ans;
}
type BinaryIndexedTree struct {
	n int
	c []int
}

func NewBinaryIndexedTree(n int) *BinaryIndexedTree {
	return &BinaryIndexedTree{
		n: n,
		c: make([]int, n+1),
	}
}

func (bit *BinaryIndexedTree) update(x int, delta int) {
	for x <= bit.n {
		bit.c[x] += delta
		x += x & -x
	}
}

func (bit *BinaryIndexedTree) query(x int) int {
	sum := 0
	for x > 0 {
		sum += bit.c[x]
		x -= x & -x
	}
	return sum
}

func countRatioSubarrays(nums []int, a int, b int) int64 {
	n := len(nums)

	s := make([]int64, n+1)

	for i, x := range nums {
		if x%2 == 1 {
			s[i+1] = s[i] + int64(a)
		} else {
			s[i+1] = s[i] - int64(b)
		}
	}

	st := append([]int64{}, s...)
	sort.Slice(st, func(i, j int) bool {
		return st[i] < st[j]
	})

	uniq := make([]int64, 0, len(st))
	for _, x := range st {
		if len(uniq) == 0 || uniq[len(uniq)-1] != x {
			uniq = append(uniq, x)
		}
	}

	bit := NewBinaryIndexedTree(len(uniq) + 1)

	var ans int64

	for _, v := range s {
		x := sort.Search(len(uniq), func(i int) bool {
			return uniq[i] >= v
		}) + 1

		ans += int64(bit.query(x))
		bit.update(x, 1)
	}

	return ans
}
Try this approach in the editor

Complexity analysis

ApproachTimeSpaceWhen to Use
Brute ForceO(n^2)O(1)Small arrays
Prefix Sum with Hash MapO(n)O(n)Large arrays

Frequently asked questions

Is Count Subarrays With Even Odd Ratio II easy or hard?

This problem is classified as hard due to its requirement for an optimal O(n) solution.

Count Subarrays With Even Odd Ratio II Python/Java solution

Solutions in Python and Java are available on FleetCode, using the prefix sum and hash map approach.

How to solve Count Subarrays With Even Odd Ratio II in O(n)?

Use a prefix sum array to track cumulative counts of even and odd numbers and a hash map to store frequency of specific ratios.

What is the best approach for Count Subarrays With Even Odd Ratio II?

The best approach is using prefix sum with a hash map, which achieves O(n) time complexity.

Is Count Subarrays With Even Odd Ratio II asked at Google/Amazon/Meta?

Yes, this problem is known to be asked at top tech companies like Google, Amazon, and Meta.

What data structure is used in Count Subarrays With Even Odd Ratio II?

A hash map is used to store the frequency of specific ratios in the optimal solution.

What is the time complexity of Count Subarrays With Even Odd Ratio II?

The optimal time complexity is O(n) using the prefix sum and hash map approach.

Comments

Now write it yourselfClose this page and solve Count Subarrays With Even Odd Ratio II in the editor, without looking.
Practise Count Subarrays With Even Odd Ratio II