Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion .mvn/maven.config
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
-T4
-ntp
-ntp
-Dmaven.compiler.fork=true
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.PHONY: tests releases

tests:
mvn clean install test

releases:
mvn clean install verify test jacoco:report
20 changes: 19 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

<buildtime.output.log>true</buildtime.output.log>

<lombok.version>1.18.32</lombok.version>
<lombok.version>1.18.40</lombok.version>
<mockito.version>5.20.0</mockito.version>
<junit-jupiter.version>5.10.2</junit-jupiter.version>
<junit-platform.version>1.10.2</junit-platform.version>
Expand Down Expand Up @@ -135,6 +135,12 @@
<version>${junit-platform.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-api</artifactId>
<version>${junit-platform.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.instancio</groupId>
<artifactId>instancio-junit</artifactId>
Expand Down Expand Up @@ -242,8 +248,16 @@
<source>${java.version}</source>
<target>${java.version}</target>
<showWarnings>false</showWarnings>
<release>${java.version}</release>
<showDeprecation>false</showDeprecation>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
Expand All @@ -259,6 +273,10 @@
<exclude>*com.shortthirdman.primekit.common.*</exclude>
<exclude>*com.shortthirdman.primekit.core.*</exclude>
</excludes>
<argLine>
-Dnet.bytebuddy.experimental=true
--add-opens java.net.http/java.net.http=ALL-UNNAMED
</argLine>
<properties>
<configurationParameters>
junit.jupiter.extensions.autodetection.enabled = true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.shortthirdman.primekit.hackerearth;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* Manages the lifecycle, renewal, and state evaluation of authentication tokens.
* <p>
* This class tracks token creation and reset commands over discrete time units,
* enforcing global expiration limits and determining token availability at the
* conclusion of event processing.
* </p>
*
* @author ShortThirdMan
* @since 1.2.1
*/
public class TokenExpiryTracker {

private static final int CMD_TYPE_INDEX = 0;
private static final int CMD_TOKEN_ID_INDEX = 1;
private static final int CMD_TIME_INDEX = 2;

private static final int ACTION_CREATE = 0;
private static final int ACTION_RESET = 1;

/**
* Calculates the number of tokens that remain active after executing all specified commands.
* <p>
* A token is active immediately upon creation at time {@code T} and expires at {@code T + expiryLimit}.
* Subsequent reset commands at time {@code T} are valid only if the token already exists and has not yet
* expired (i.e., its current expiration time is greater than or equal to {@code T}).
* </p>
* <p>
* After processing all commands, a token is considered active if its expiration time is strictly
* greater than the timestamp of the last executed command.
* </p>
*
* @param expiryLimit the fixed lifespan added to the execution timestamp upon token creation or reset;
* must be greater than or equal to 1
* @param commands a chronological list of 3-element integer tuples representing operations:
* <ul>
* <li>{@code [0, tokenId, T]} - Creates a new token with ID {@code tokenId} at time {@code T}.</li>
* <li>{@code [1, tokenId, T]} - Resets the expiration of an existing token with ID {@code tokenId} at time {@code T}.</li>
* </ul>
* Must be sorted in non-decreasing order of {@code T}.
* @return the total count of active tokens remaining after all commands have been evaluated;
* returns {@code 0} if {@code commands} is empty
* @throws NullPointerException if {@code commands} is {@code null} or contains {@code null} entries
* @throws IllegalArgumentException if {@code expiryLimit} is non-positive or if any command does not
* contain exactly three elements
*/
public int numberOfTokens(int expiryLimit, List<List<Integer>> commands) {
Objects.requireNonNull(commands, "commands list must not be null");
if (expiryLimit <= 0) {
throw new IllegalArgumentException("expiryLimit must be positive: " + expiryLimit);
}
if (commands.isEmpty()) {
return 0;
}

Map<Integer, Integer> tokenExpiries = new HashMap<>();

for (List<Integer> cmd : commands) {
Objects.requireNonNull(cmd, "command entry must not be null");
if (cmd.size() != 3) {
throw new IllegalArgumentException("Command must contain exactly 3 integers: [type, tokenId, T]");
}

int type = cmd.get(CMD_TYPE_INDEX);
int tokenId = cmd.get(CMD_TOKEN_ID_INDEX);
int timestamp = cmd.get(CMD_TIME_INDEX);

if (type == ACTION_CREATE) {
tokenExpiries.put(tokenId, timestamp + expiryLimit);
} else if (type == ACTION_RESET) {
Integer currentExpiry = tokenExpiries.get(tokenId);
if (currentExpiry != null && currentExpiry >= timestamp) {
tokenExpiries.put(tokenId, timestamp + expiryLimit);
}
}
}

int finalTimestamp = commands.getLast().get(CMD_TIME_INDEX);

return (int) tokenExpiries.values().stream()
.filter(expiry -> expiry > finalTimestamp)
.count();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.shortthirdman.primekit.hackerearth;

import java.util.List;
import java.util.Objects;

/**
* Solves the optimal upgrade selection problem under a fixed currency constraint.
*
* <p>Each available upgrade index {@code i} incurs a given cost and yields an
* enhancement gain equal to {@code 2^i}[cite: 1]. Because every power of two is strictly greater
* than the sum of all preceding powers of two (i.e., {@code \sum_{j=0}^{i-1} 2^j = 2^i - 1 < 2^i}),
* the problem exhibits the greedy-choice property. This optimizer selects upgrades
* greedily starting from the highest available power down to zero.
*
* <p><strong>Thread Safety:</strong> This class is stateless, immutable, and thread-safe.
*
* @since 1.2.1
* @author ShortThirdMan
*/
public class UpgradeEnhancementOptimizer {

private static final int MOD = 1_000_000_007;

/**
* Calculates the maximum enhancement obtainable without exceeding the provided budget.
*
* <p>Enhancement values grow exponentially such that the item at index {@code i}
* contributes {@code 2^i} enhancement[cite: 1]. The returned sum is reduced modulo {@code 10^9 + 7}[cite: 1].
*
* <h4>Algorithm Details</h4>
* <ul>
* <li><strong>Precomputes</strong> powers of two modulo {@code 1,000,000,007}.</li>
* <li><strong>Greedy Selection:</strong> Evaluates items in descending index order
* ({@code n - 1} down to {@code 0}), deducting the item cost whenever sufficient
* budget remains.</li>
* </ul>
*
* <h4>Complexity</h4>
* <ul>
* <li>Time Complexity: {@code O(n)}, where {@code n} is the size of {@code upgradeCosts}.</li>
* <li>Space Complexity: {@code O(n)} auxiliary memory for modular exponent precomputations.</li>
* </ul>
*
* @param upgradeCosts non-null list of non-negative integers representing upgrade costs,
* where element at index {@code i} yields enhancement {@code 2^i}[cite: 1]
* @param budget maximum spendable currency, must be non-negative
* @return the maximum enhancement score achievable within budget, modulo {@code 10^9 + 7}[cite: 1]
* @throws NullPointerException if {@code upgradeCosts} is {@code null}
* @throws IllegalArgumentException if {@code budget} is negative
*/
public int optimizeInAppUpgrades(List<Integer> upgradeCosts, int budget) {
Objects.requireNonNull(upgradeCosts, "upgradeCosts must not be null");
if (budget < 0) {
throw new IllegalArgumentException("budget cannot be negative: " + budget);
}

int n = upgradeCosts.size();
if (n == 0) {
return 0;
}

// Precompute powers of 2: 2^0, 2^1, ..., 2^(n-1) modulo 10^9 + 7
int[] pow2 = new int[n];
pow2[0] = 1;
for (int i = 1; i < n; i++) {
pow2[i] = (pow2[i - 1] * 2) % MOD;
}

long remainingBudget = budget;
int totalEnhancement = 0;

for (int i = n - 1; i >= 0; i--) {
int cost = upgradeCosts.get(i);
if (remainingBudget >= cost) {
remainingBudget -= cost;
totalEnhancement += pow2[i];
if (totalEnhancement >= MOD) {
totalEnhancement -= MOD;
}
}
}

return totalEnhancement;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class WordLadders {
* @param beginWord the word to begin with
* @param endWord the word to end with
* @param wordList the list of words
* @return
* @return the list of ladders
*/
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> result = new ArrayList<>();
Expand All @@ -33,7 +33,7 @@ public List<List<String>> findLadders(String beginWord, String endWord, List<Str
while (!queue.isEmpty()) {
LinkedWordNode top = queue.poll();

//top if have shorter result already
//top if you have shorter result already
if (!result.isEmpty() && top.getDepth() > minLen) {
return result;
}
Expand Down Expand Up @@ -61,7 +61,7 @@ public List<List<String>> findLadders(String beginWord, String endWord, List<Str
Collections.reverse(aResult);
result.add(aResult);

//stop if get shorter result
//stop if you get shorter result
if (top.getDepth() <= minLen) {
minLen = top.getDepth();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shortthirdman.primekit;

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;

@Suite
@SuiteDisplayName("CodeSignal JUnit Platform Suite")
@SelectPackages("com.shortthirdman.primekit.codesignal")
@IncludeClassNamePatterns(".*Test")
class PrimeKitCodeSignalSuite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shortthirdman.primekit;

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;

@Suite
@SuiteDisplayName("CoderByte JUnit Platform Suite")
@SelectPackages("com.shortthirdman.primekit.coderbyte")
@IncludeClassNamePatterns(".*Test")
class PrimeKitCoderByteSuite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shortthirdman.primekit;

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;

@Suite
@SuiteDisplayName("Codility JUnit Platform Suite")
@SelectPackages("com.shortthirdman.primekit.codility")
@IncludeClassNamePatterns(".*Test")
class PrimeKitCodilitySuite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shortthirdman.primekit;

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;

@Suite
@SuiteDisplayName("HackerEarth JUnit Platform Suite")
@SelectPackages("com.shortthirdman.primekit.hackerearth")
@IncludeClassNamePatterns(".*Test")
class PrimeKitHackerEarthSuite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shortthirdman.primekit;

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;

@Suite
@SuiteDisplayName("HackerRank JUnit Platform Suite")
@SelectPackages("com.shortthirdman.primekit.hackerrank")
@IncludeClassNamePatterns(".*Test")
class PrimeKitHackerRankSuite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.shortthirdman.primekit;

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;

@Suite
@SuiteDisplayName("LeetCode JUnit Platform Suite")
@SelectPackages("com.shortthirdman.primekit.leetcode")
@IncludeClassNamePatterns(".*Test")
class PrimeKitLeetCodeSuite {
}
Loading
Loading