Skip to content

Added tasks 3507-3510 #1957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package g3501_3600.s3507_minimum_pair_removal_to_sort_array_i;

// #Easy #Array #Hash_Table #Heap_Priority_Queue #Simulation #Linked_List #Ordered_Set
// #Doubly_Linked_List #2025_04_09_Time_1_ms_(100.00%)_Space_42.96_MB_(53.67%)

public class Solution {
public int minimumPairRemoval(int[] nums) {
int operations = 0;
while (!isNonDecreasing(nums)) {
int minSum = Integer.MAX_VALUE;
int index = 0;
// Find the leftmost pair with minimum sum
for (int i = 0; i < nums.length - 1; i++) {
int sum = nums[i] + nums[i + 1];
if (sum < minSum) {
minSum = sum;
index = i;
}
}
// Merge the pair at index
int[] newNums = new int[nums.length - 1];
int j = 0;
int i = 0;
while (i < nums.length) {
if (i == index) {
newNums[j++] = nums[i] + nums[i + 1];
// Skip the next one since it's merged
i++;
} else {
newNums[j++] = nums[i];
}
i++;
}
nums = newNums;
operations++;
}
return operations;
}

private boolean isNonDecreasing(int[] nums) {
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1]) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
3507\. Minimum Pair Removal to Sort Array I

Easy

Given an array `nums`, you can perform the following operation any number of times:

* Select the **adjacent** pair with the **minimum** sum in `nums`. If multiple such pairs exist, choose the leftmost one.
* Replace the pair with their sum.

Return the **minimum number of operations** needed to make the array **non-decreasing**.

An array is said to be **non-decreasing** if each element is greater than or equal to its previous element (if it exists).

**Example 1:**

**Input:** nums = [5,2,3,1]

**Output:** 2

**Explanation:**

* The pair `(3,1)` has the minimum sum of 4. After replacement, `nums = [5,2,4]`.
* The pair `(2,4)` has the minimum sum of 6. After replacement, `nums = [5,6]`.

The array `nums` became non-decreasing in two operations.

**Example 2:**

**Input:** nums = [1,2,2]

**Output:** 0

**Explanation:**

The array `nums` is already sorted.

**Constraints:**

* `1 <= nums.length <= 50`
* `-1000 <= nums[i] <= 1000`
107 changes: 107 additions & 0 deletions src/main/java/g3501_3600/s3508_implement_router/Router.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package g3501_3600.s3508_implement_router;

// #Medium #Array #Hash_Table #Binary_Search #Design #Ordered_Set #Queue
// #2025_04_09_Time_137_ms_(100.00%)_Space_116.63_MB_(91.98%)

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

@SuppressWarnings("java:S135")
public class Router {
private final int size;
private int cur;
private final Queue<int[]> q;
private final HashMap<Integer, ArrayList<int[]>> map;

public Router(int memoryLimit) {
q = new LinkedList<>();
map = new HashMap<>();
size = memoryLimit;
cur = 0;
}

public boolean addPacket(int source, int destination, int timestamp) {
if (map.containsKey(destination)) {
boolean found = false;
ArrayList<int[]> list = map.get(destination);
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i)[1] < timestamp) {
break;
} else if (list.get(i)[0] == source) {
found = true;
break;
}
}
if (found) {
return false;
}
}
if (map.containsKey(destination)) {
ArrayList<int[]> list = map.get(destination);
list.add(new int[] {source, timestamp});
cur++;
q.offer(new int[] {source, destination, timestamp});
} else {
ArrayList<int[]> temp = new ArrayList<>();
temp.add(new int[] {source, timestamp});
cur++;
map.put(destination, temp);
q.offer(new int[] {source, destination, timestamp});
}
if (cur > size) {
forwardPacket();
}
return true;
}

public int[] forwardPacket() {
if (q.isEmpty()) {
return new int[] {};
}
int[] temp = q.poll();
ArrayList<int[]> list = map.get(temp[1]);
list.remove(0);
if (list.isEmpty()) {
map.remove(temp[1]);
}
cur--;
return temp;
}

public int getCount(int destination, int startTime, int endTime) {
if (map.containsKey(destination)) {
ArrayList<int[]> list = map.get(destination);
int lower = -1;
int higher = -1;
for (int i = 0; i < list.size(); i++) {
if (list.get(i)[1] >= startTime) {
lower = i;
break;
}
}
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i)[1] <= endTime) {
higher = i;
break;
}
}
if (lower == -1 || higher == -1) {
return 0;
} else {
return Math.max(0, higher - lower + 1);
}
} else {
return 0;
}
}
}

/*
* Your Router object will be instantiated and called as such:
* Router obj = new Router(memoryLimit);
* boolean param_1 = obj.addPacket(source,destination,timestamp);
* int[] param_2 = obj.forwardPacket();
* int param_3 = obj.getCount(destination,startTime,endTime);
*/
79 changes: 79 additions & 0 deletions src/main/java/g3501_3600/s3508_implement_router/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
3508\. Implement Router

Medium

Design a data structure that can efficiently manage data packets in a network router. Each data packet consists of the following attributes:

* `source`: A unique identifier for the machine that generated the packet.
* `destination`: A unique identifier for the target machine.
* `timestamp`: The time at which the packet arrived at the router.

Implement the `Router` class:

`Router(int memoryLimit)`: Initializes the Router object with a fixed memory limit.

* `memoryLimit` is the **maximum** number of packets the router can store at any given time.
* If adding a new packet would exceed this limit, the **oldest** packet must be removed to free up space.

`bool addPacket(int source, int destination, int timestamp)`: Adds a packet with the given attributes to the router.

* A packet is considered a duplicate if another packet with the same `source`, `destination`, and `timestamp` already exists in the router.
* Return `true` if the packet is successfully added (i.e., it is not a duplicate); otherwise return `false`.

`int[] forwardPacket()`: Forwards the next packet in FIFO (First In First Out) order.

* Remove the packet from storage.
* Return the packet as an array `[source, destination, timestamp]`.
* If there are no packets to forward, return an empty array.

`int getCount(int destination, int startTime, int endTime)`:

* Returns the number of packets currently stored in the router (i.e., not yet forwarded) that have the specified destination and have timestamps in the inclusive range `[startTime, endTime]`.

**Note** that queries for `addPacket` will be made in increasing order of `timestamp`.

**Example 1:**

**Input:**
["Router", "addPacket", "addPacket", "addPacket", "addPacket", "addPacket", "forwardPacket", "addPacket", "getCount"]
[[3], [1, 4, 90], [2, 5, 90], [1, 4, 90], [3, 5, 95], [4, 5, 105], [], [5, 2, 110], [5, 100, 110]]

**Output:**
[null, true, true, false, true, true, [2, 5, 90], true, 1]

**Explanation**

Router router = new Router(3); // Initialize Router with memoryLimit of 3.
router.addPacket(1, 4, 90); // Packet is added. Return True.
router.addPacket(2, 5, 90); // Packet is added. Return True.
router.addPacket(1, 4, 90); // This is a duplicate packet. Return False.
router.addPacket(3, 5, 95); // Packet is added. Return True
router.addPacket(4, 5, 105); // Packet is added, `[1, 4, 90]` is removed as number of packets exceeds memoryLimit. Return True.
router.forwardPacket(); // Return `[2, 5, 90]` and remove it from router.
router.addPacket(5, 2, 110); // Packet is added. Return True.
router.getCount(5, 100, 110); // The only packet with destination 5 and timestamp in the inclusive range `[100, 110]` is `[4, 5, 105]`. Return 1.

**Example 2:**

**Input:**
["Router", "addPacket", "forwardPacket", "forwardPacket"]
[[2], [7, 4, 90], [], []]

**Output:**
[null, true, [7, 4, 90], []]

**Explanation**

Router router = new Router(2); // Initialize `Router` with `memoryLimit` of 2.
router.addPacket(7, 4, 90); // Return True.
router.forwardPacket(); // Return `[7, 4, 90]`.
router.forwardPacket(); // There are no packets left, return `[]`.

**Constraints:**

* <code>2 <= memoryLimit <= 10<sup>5</sup></code>
* <code>1 <= source, destination <= 2 * 10<sup>5</sup></code>
* <code>1 <= timestamp <= 10<sup>9</sup></code>
* <code>1 <= startTime <= endTime <= 10<sup>9</sup></code>
* At most <code>10<sup>5</sup></code> calls will be made to `addPacket`, `forwardPacket`, and `getCount` methods altogether.
* queries for `addPacket` will be made in increasing order of `timestamp`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package g3501_3600.s3509_maximum_product_of_subsequences_with_an_alternating_sum_equal_to_k;

// #Hard #Array #Hash_Table #Dynamic_Programming
// #2025_04_09_Time_141_ms_(89.52%)_Space_46.06_MB_(99.56%)

import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("java:S6541")
public class Solution {
static class StateKey {
int prod;
int parity;

StateKey(int prod, int parity) {
this.prod = prod;
this.parity = parity;
}

@Override
public int hashCode() {
return prod * 31 + parity;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof StateKey)) {
return false;
}
StateKey other = (StateKey) obj;
return this.prod == other.prod && this.parity == other.parity;
}
}

private static BitSet shift(BitSet bs, int shiftVal, int size) {
BitSet res = new BitSet(size);
if (shiftVal >= 0) {
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
int newIdx = i + shiftVal;
if (newIdx < size) {
res.set(newIdx);
}
}
} else {
int shiftRight = -shiftVal;
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
int newIdx = i - shiftRight;
if (newIdx >= 0) {
res.set(newIdx);
}
}
}
return res;
}

public int maxProduct(int[] nums, int k, int limit) {
int[] melkarvothi = nums.clone();
int offset = 1000;
int size = 2100;
Map<StateKey, BitSet> dp = new HashMap<>();
for (int x : melkarvothi) {
Map<StateKey, BitSet> newStates = new HashMap<>();
for (Map.Entry<StateKey, BitSet> entry : dp.entrySet()) {
StateKey key = entry.getKey();
int currentProd = key.prod;
int newProd;
if (x == 0) {
newProd = 0;
} else {
if (currentProd == 0) {
newProd = 0;
} else if (currentProd == -1) {
newProd = -1;
} else {
long mult = (long) currentProd * x;
if (mult > limit) {
newProd = -1;
} else {
newProd = (int) mult;
}
}
}
int newParity = 1 - key.parity;
BitSet bs = entry.getValue();
BitSet shifted;
if (key.parity == 0) {
shifted = shift(bs, x, size);
} else {
shifted = shift(bs, -x, size);
}
StateKey newKey = new StateKey(newProd, newParity);
BitSet current = newStates.get(newKey);
if (current == null) {
current = new BitSet(size);
newStates.put(newKey, current);
}
current.or(shifted);
}
if (x == 0 || x <= limit) {
int parityStart = 1;
StateKey newKey = new StateKey(x, parityStart);
BitSet bs = newStates.get(newKey);
if (bs == null) {
bs = new BitSet(size);
newStates.put(newKey, bs);
}
int pos = x + offset;
if (pos >= 0 && pos < size) {
bs.set(pos);
}
}
for (Map.Entry<StateKey, BitSet> entry : newStates.entrySet()) {
StateKey key = entry.getKey();
BitSet newBS = entry.getValue();
BitSet oldBS = dp.get(key);
if (oldBS == null) {
dp.put(key, newBS);
} else {
oldBS.or(newBS);
}
}
}
int answer = -1;
int targetIdx = k + offset;
for (Map.Entry<StateKey, BitSet> entry : dp.entrySet()) {
StateKey key = entry.getKey();
if (key.prod == -1) {
continue;
}
BitSet bs = entry.getValue();
if (targetIdx >= 0 && targetIdx < size && bs.get(targetIdx)) {
answer = Math.max(answer, key.prod);
}
}
return answer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
3509\. Maximum Product of Subsequences With an Alternating Sum Equal to K

Hard

You are given an integer array `nums` and two integers, `k` and `limit`. Your task is to find a non-empty ****subsequences**** of `nums` that:

* Has an **alternating sum** equal to `k`.
* **Maximizes** the product of all its numbers _without the product exceeding_ `limit`.

Return the _product_ of the numbers in such a subsequence. If no subsequence satisfies the requirements, return -1.

The **alternating sum** of a **0-indexed** array is defined as the **sum** of the elements at **even** indices **minus** the **sum** of the elements at **odd** indices.

**Example 1:**

**Input:** nums = [1,2,3], k = 2, limit = 10

**Output:** 6

**Explanation:**

The subsequences with an alternating sum of 2 are:

* `[1, 2, 3]`
* Alternating Sum: `1 - 2 + 3 = 2`
* Product: `1 * 2 * 3 = 6`
* `[2]`
* Alternating Sum: 2
* Product: 2

The maximum product within the limit is 6.

**Example 2:**

**Input:** nums = [0,2,3], k = -5, limit = 12

**Output:** \-1

**Explanation:**

A subsequence with an alternating sum of exactly -5 does not exist.

**Example 3:**

**Input:** nums = [2,2,3,3], k = 0, limit = 9

**Output:** 9

**Explanation:**

The subsequences with an alternating sum of 0 are:

* `[2, 2]`
* Alternating Sum: `2 - 2 = 0`
* Product: `2 * 2 = 4`
* `[3, 3]`
* Alternating Sum: `3 - 3 = 0`
* Product: `3 * 3 = 9`
* `[2, 2, 3, 3]`
* Alternating Sum: `2 - 2 + 3 - 3 = 0`
* Product: `2 * 2 * 3 * 3 = 36`

The subsequence `[2, 2, 3, 3]` has the greatest product with an alternating sum equal to `k`, but `36 > 9`. The next greatest product is 9, which is within the limit.

**Constraints:**

* `1 <= nums.length <= 150`
* `0 <= nums[i] <= 12`
* <code>-10<sup>5</sup> <= k <= 10<sup>5</sup></code>
* `1 <= limit <= 5000`
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package g3501_3600.s3510_minimum_pair_removal_to_sort_array_ii;

// #Hard #Array #Hash_Table #Heap_Priority_Queue #Simulation #Linked_List #Ordered_Set
// #Doubly_Linked_List #2025_04_09_Time_289_ms_(99.58%)_Space_82.88_MB_(17.23%)

public class Solution {
private static class Segment {
private final int start;
private final int end;
private Segment left;
private Segment right;
private int lIdx;
private long lNum;
private int rIdx;
private long rNum;
private boolean ok;
private long minSum;
private int li;
private int ri;

public static Segment init(int[] arr) {
return new Segment(arr, 0, arr.length - 1);
}

public Segment(int[] arr, int s, int e) {
start = s;
end = e;
if (s >= e) {
lIdx = rIdx = s;
lNum = rNum = arr[s];
minSum = Long.MAX_VALUE;
ok = true;
return;
}
int mid = s + ((e - s) >> 1);
left = new Segment(arr, s, mid);
right = new Segment(arr, mid + 1, e);
merge();
}

private void merge() {
lIdx = left.lIdx;
lNum = left.lNum;
rIdx = right.rIdx;
rNum = right.rNum;
ok = left.ok && right.ok && left.rNum <= right.lNum;
minSum = left.minSum;
li = left.li;
ri = left.ri;
if (left.rNum + right.lNum < minSum) {
minSum = left.rNum + right.lNum;
li = left.rIdx;
ri = right.lIdx;
}
if (right.minSum < minSum) {
minSum = right.minSum;
li = right.li;
ri = right.ri;
}
}

public void update(int i, long n) {
if (start <= i && end >= i) {
if (start >= end) {
lNum = rNum = n;
} else {
left.update(i, n);
right.update(i, n);
merge();
}
}
}

public Segment remove(int i) {
if (start > i || end < i) {
return this;
} else if (start >= end) {
return null;
}
left = left.remove(i);
right = right.remove(i);
if (null == left) {
return right;
} else if (null == right) {
return left;
}
merge();
return this;
}
}

public int minimumPairRemoval(int[] nums) {
Segment root = Segment.init(nums);
int res = 0;
while (!root.ok) {
int l = root.li;
int r = root.ri;
root.update(l, root.minSum);
root = root.remove(r);
res++;
}
return res;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
3510\. Minimum Pair Removal to Sort Array II

Hard

Given an array `nums`, you can perform the following operation any number of times:

* Select the **adjacent** pair with the **minimum** sum in `nums`. If multiple such pairs exist, choose the leftmost one.
* Replace the pair with their sum.

Return the **minimum number of operations** needed to make the array **non-decreasing**.

An array is said to be **non-decreasing** if each element is greater than or equal to its previous element (if it exists).

**Example 1:**

**Input:** nums = [5,2,3,1]

**Output:** 2

**Explanation:**

* The pair `(3,1)` has the minimum sum of 4. After replacement, `nums = [5,2,4]`.
* The pair `(2,4)` has the minimum sum of 6. After replacement, `nums = [5,6]`.

The array `nums` became non-decreasing in two operations.

**Example 2:**

**Input:** nums = [1,2,2]

**Output:** 0

**Explanation:**

The array `nums` is already sorted.

**Constraints:**

* <code>1 <= nums.length <= 10<sup>5</sup></code>
* <code>-10<sup>9</sup> <= nums[i] <= 10<sup>9</sup></code>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package g3501_3600.s3507_minimum_pair_removal_to_sort_array_i;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.Test;

class SolutionTest {
@Test
void minimumPairRemoval() {
assertThat(new Solution().minimumPairRemoval(new int[] {5, 2, 3, 1}), equalTo(2));
}

@Test
void minimumPairRemoval2() {
assertThat(new Solution().minimumPairRemoval(new int[] {1, 2, 2}), equalTo(0));
}
}
65 changes: 65 additions & 0 deletions src/test/java/g3501_3600/s3508_implement_router/RouterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package g3501_3600.s3508_implement_router;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.Test;

class RouterTest {
@Test
void router() {
// Initialize Router with memoryLimit of 3.
Router router = new Router(3);
// Packet is added. Return True.
assertThat(router.addPacket(1, 4, 90), equalTo(true));
// Packet is added. Return True.
assertThat(router.addPacket(2, 5, 90), equalTo(true));
// This is a duplicate packet. Return False.
assertThat(router.addPacket(1, 4, 90), equalTo(false));
// Packet is added. Return True
assertThat(router.addPacket(3, 5, 95), equalTo(true));
// Packet is added, [1, 4, 90] is removed as number of packets exceeds memoryLimit. Return
// True.
assertThat(router.addPacket(4, 5, 105), equalTo(true));
// Return [2, 5, 90] and remove it from router.
assertThat(router.forwardPacket(), equalTo(new int[] {2, 5, 90}));
// Packet is added. Return True.
assertThat(router.addPacket(5, 2, 110), equalTo(true));
// The only packet with destination 5 and timestamp in the inclusive range
assertThat(router.getCount(5, 100, 110), equalTo(1));
}

@Test
void router2() {
// Initialize Router with memoryLimit of 2.
Router router = new Router(2);
// Packet is added. Return True.
assertThat(router.addPacket(7, 4, 90), equalTo(true));
// Return [7, 4, 90] and remove it from router.
assertThat(router.forwardPacket(), equalTo(new int[] {7, 4, 90}));
// Return [] and remove it from router.
assertThat(router.forwardPacket(), equalTo(new int[] {}));
}

@Test
void router3() {
// Initialize Router with memoryLimit of 3.
Router router = new Router(3);
// Packet is added. Return True.
assertThat(router.addPacket(1, 4, 6), equalTo(true));
// The only packet with destination 0 and timestamp in the inclusive range
assertThat(router.getCount(4, 1, 4), equalTo(0));
}

@Test
void router4() {
// Initialize Router with memoryLimit of 2.
Router router = new Router(2);
// Packet is added. Return True.
assertThat(router.addPacket(2, 5, 1), equalTo(true));
// Return [2, 5, 1] and remove it from router.
assertThat(router.forwardPacket(), equalTo(new int[] {2, 5, 1}));
// The only packet with destination 0 and timestamp in the inclusive range
assertThat(router.getCount(5, 1, 1), equalTo(0));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package g3501_3600.s3509_maximum_product_of_subsequences_with_an_alternating_sum_equal_to_k;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.Test;

class SolutionTest {
@Test
void maxProduct() {
assertThat(new Solution().maxProduct(new int[] {1, 2, 3}, 2, 10), equalTo(6));
}

@Test
void maxProduct2() {
assertThat(new Solution().maxProduct(new int[] {0, 2, 3}, -5, 12), equalTo(-1));
}

@Test
void maxProduct3() {
assertThat(new Solution().maxProduct(new int[] {2, 2, 3, 3}, 0, 9), equalTo(9));
}

@Test
void maxProduct4() {
assertThat(new Solution().maxProduct(new int[] {12, 0, 9}, 21, 20), equalTo(0));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package g3501_3600.s3510_minimum_pair_removal_to_sort_array_ii;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.jupiter.api.Test;

class SolutionTest {
@Test
void minimumPairRemoval() {
assertThat(new Solution().minimumPairRemoval(new int[] {5, 2, 3, 1}), equalTo(2));
}

@Test
void minimumPairRemoval2() {
assertThat(new Solution().minimumPairRemoval(new int[] {1, 2, 2}), equalTo(0));
}
}