Problem solution · Java

Maximize Active Section with Trade II

Maximize Active Section with Trade II: a Java solution using sliding window or two pointers. Learn the idea, check the complexity, and read the full code, with credit to walkccc LeetCode Solutions.

Technique
Sliding window or two pointers
Source
walkccc LeetCode Solutions
Length
111 lines
Start with the idea.

Try the problem first. If you get stuck, read the approach below, then write your own solution. The full code is at the bottom.

Approach

Sliding window or two pointers

For Maximize Active Section with Trade II, the implementation maintains a moving interval and updates only the information that enters or leaves the window.

  1. Choose the invariant that makes a window valid or useful.
  2. Advance the right boundary and add the new element.
  3. Move the left boundary only as needed while maintaining the invariant and updating the answer.

Code notes

  • 111 lines of Java from the credited upstream file 3501.java.
  • The implementation visibly relies on sequence storage.
  • 5 loop blocks detected.

Complexity

Confirm that neither pointer moves backwards; if so, the scan is usually linear apart from the window’s data-structure operations.

Check the problem constraints before deciding whether this complexity will pass.

Source

Code and credit

This code comes from walkccc LeetCode Solutions by P.-Y. Chen (walkccc) and is used under the MIT licence.

Full codeMaximize Active Section with Trade II · JavaJava
Use this to learn the idea, then write your own version.
class Group {  public int start;  public int length;  public Group(int start, int length) {    this.start = start;    this.length = length;  }} class SparseTable {  public SparseTable(int[] nums) {    n = nums.length;    st = new int[bitLength(n) + 1][n + 1];    System.arraycopy(nums, 0, st[0], 0, n);    for (int i = 1; i <= st.length; ++i)      for (int j = 0; j + (1 << i) <= n; ++j)        st[i][j] = Math.max(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);  }   // Returns max(nums[l..r])  public int query(int l, int r) {    final int i = bitLength(r - l + 1) - 1;    return Math.max(st[i][l], st[i][r - (1 << i) + 1]);  }   private final int n;  private final int[][] st; // st[i][j] := max(nums[j..j + 2^i - 1])   private int bitLength(int n) {    return Integer.SIZE - Integer.numberOfLeadingZeros(n);  }} class Solution {  public List<Integer> maxActiveSectionsAfterTrade(String s, int[][] queries) {    final int n = s.length();    final int ones = (int) s.chars().filter(c -> c == '1').count();    final Pair<List<Group>, int[]> zeroGroupsInfo = getZeroGroups(s);    final List<Group> zeroGroups = zeroGroupsInfo.getKey();    final int[] zeroGroupIndex = zeroGroupsInfo.getValue();     if (zeroGroups.isEmpty())      return Collections.nCopies(queries.length, ones);     final SparseTable st = new SparseTable(getZeroMergeLengths(zeroGroups));    final List<Integer> ans = new ArrayList<>();     for (int[] query : queries) {      final int l = query[0];      final int r = query[1];      final int left = zeroGroupIndex[l] == -1 ? -1                                               : (zeroGroups.get(zeroGroupIndex[l]).length -                                                  (l - zeroGroups.get(zeroGroupIndex[l]).start));      final int right =          zeroGroupIndex[r] == -1 ? -1 : (r - zeroGroups.get(zeroGroupIndex[r]).start + 1);      final Pair<Integer, Integer> adjacentIndices = mapToAdjacentGroupIndices(          zeroGroupIndex[l] + 1, s.charAt(r) == '1' ? zeroGroupIndex[r] : zeroGroupIndex[r] - 1);      final int startAdjacentGroupIndex = adjacentIndices.getKey();      final int endAdjacentGroupIndex = adjacentIndices.getValue();       int activeSections = ones;      if (s.charAt(l) == '0' && s.charAt(r) == '0' && zeroGroupIndex[l] + 1 == zeroGroupIndex[r])        activeSections = Math.max(activeSections, ones + left + right);      else if (startAdjacentGroupIndex <= endAdjacentGroupIndex)        activeSections = Math.max(activeSections,                                  ones + st.query(startAdjacentGroupIndex, endAdjacentGroupIndex));      if (s.charAt(l) == '0' &&          zeroGroupIndex[l] + 1 <= (s.charAt(r) == '1' ? zeroGroupIndex[r] : zeroGroupIndex[r] - 1))        activeSections =            Math.max(activeSections, ones + left + zeroGroups.get(zeroGroupIndex[l] + 1).length);      if (s.charAt(r) == '0' && zeroGroupIndex[l] < zeroGroupIndex[r] - 1)        activeSections =            Math.max(activeSections, ones + right + zeroGroups.get(zeroGroupIndex[r] - 1).length);      ans.add(activeSections);    }     return ans;  }   // Returns the zero groups and the index of the zero group that contains the i-th character  private Pair<List<Group>, int[]> getZeroGroups(String s) {    final List<Group> zeroGroups = new ArrayList<>();    final int[] zeroGroupIndex = new int[s.length()];     for (int i = 0; i < s.length(); i++) {      if (s.charAt(i) == '0') {        if (i > 0 && s.charAt(i - 1) == '0')          zeroGroups.get(zeroGroups.size() - 1).length++;        else          zeroGroups.add(new Group(i, 1));      }      zeroGroupIndex[i] = zeroGroups.size() - 1;    }     return new Pair<>(zeroGroups, zeroGroupIndex);  }   // Returns the sums of the lengths of the adjacent groups  private int[] getZeroMergeLengths(List<Group> zeroGroups) {    final int[] zeroMergeLengths = new int[zeroGroups.size() - 1];    for (int i = 0; i < zeroGroups.size() - 1; ++i)      zeroMergeLengths[i] = zeroGroups.get(i).length + zeroGroups.get(i + 1).length;    return zeroMergeLengths;  }   // Returns the indices of the adjacent groups that contain l and r completely  private Pair<Integer, Integer> mapToAdjacentGroupIndices(int startGroupIndex, int endGroupIndex) {    return new Pair<>(startGroupIndex, endGroupIndex - 1);  }} 

Did this explanation save you time? I'm a Grade 11 student building this free library to make difficult algorithms easier to understand.

Buy me a coffee ↗