2241. Design an ATM Machine
- There is an ATM machine that stores banknotes of
5
denominations:20
,50
,100
,200
, and500
dollars. Initially the ATM is empty. The user can use the machine to deposit or withdraw any amount of money. - When withdrawing, the machine prioritizes using banknotes of larger values.
- For example, if you want to withdraw
$300
and there are2
$50
banknotes,1
$100
banknote, and1
$200
banknote, then the machine will use the$100
and$200
banknotes. - However, if you try to withdraw
$600
and there are3
$200
banknotes and1
$500
banknote, then the withdraw request will be rejected because the machine will first try to use the$500
banknote and then be unable to use banknotes to complete the remaining$100
. Note that the machine is not allowed to use the$200
banknotes instead of the$500
banknote.
- For example, if you want to withdraw
- Implement the ATM class:
-
ATM()
Initializes the ATM object. -
void deposit(int[] banknotesCount)
Deposits new banknotes in the order$20
,$50
,$100
,$200
, and$500
. -
int[] withdraw(int amount)
Returns an array of length5
of the number of banknotes that will be handed to the user in the order$20
,$50
,$100
,$200
, and$500
, and update the number of banknotes in the ATM after withdrawing. Returns[-1]
if it is not possible (do not withdraw any banknotes in this case).
-
Example 1
Input
["ATM", "deposit", "withdraw", "deposit", "withdraw", "withdraw"]
[[], [[0,0,1,2,1]], [600], [[0,1,0,1,1]], [600], [550]]
Output
[null, null, [0,0,1,0,1], null, [-1], [0,1,0,0,1]]
Explanation
ATM atm = new ATM();
atm.deposit([0,0,1,2,1]); // Deposits 1 $100 banknote, 2 $200 banknotes,
// and 1 $500 banknote.
atm.withdraw(600); // Returns [0,0,1,0,1]. The machine uses 1 $100 banknote
// and 1 $500 banknote. The banknotes left over in the
// machine are [0,0,0,2,0].
atm.deposit([0,1,0,1,1]); // Deposits 1 $50, $200, and $500 banknote.
// The banknotes in the machine are now [0,1,0,3,1].
atm.withdraw(600); // Returns [-1]. The machine will try to use a $500 banknote
// and then be unable to complete the remaining $100,
// so the withdraw request will be rejected.
// Since the request is rejected, the number of banknotes
// in the machine is not modified.
atm.withdraw(550); // Returns [0,1,0,0,1]. The machine uses 1 $50 banknote
// and 1 $500 banknote.
Method 1
【O(1) time | O(1) space】
package Leetcode.SlideWindow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhengxingxing
* @date 2025/01/04
*/
public class SubstringWithConcatenationOfAllWords {
public static List<Integer> findSubstring(String s, String[] words) {
// List to store the final result, records the starting indices of substrings that meet the condition
List<Integer> result = new ArrayList<>();
// Basic input checks, return empty result if input is null or empty
if (s == null || s.length() == 0 || words == null || words.length == 0) {
return result;
}
// Get basic information
int wordLen = words[0].length(); // Length of each word
int wordCount = words.length; // Total number of words
int totalLen = wordLen * wordCount; // Total length of all concatenated words
// If the original string's length is smaller than the required total length, it can't match, return empty result
if (s.length() < totalLen) {
return result;
}
// Step 1: Create a HashMap to count how many times each word should appear in the words array
// Key is the word, value is how many times the word should appear
Map<String, Integer> wordMap = new HashMap<>();
for (String word : words) {
wordMap.put(word, wordMap.getOrDefault(word, 0) + 1);
}
// Step 2: Iterate over all possible starting positions
// Since the length of each word is fixed, only need to iterate over wordLen offsets
// For example, if the word length is 3, we only need to start from indices 0, 1, 2 to cover all possibilities
for (int i = 0; i < wordLen; i++) {
int left = i; // Left boundary of the sliding window
int count = 0; // The number of matched words in the current window
Map<String, Integer> curMap = new HashMap<>(); // Count of words in the current window
// Step 3: Use sliding window, each time move by one word length
for (int j = i; j <= s.length() - wordLen; j += wordLen) {
// Get the word at the current position
String word = s.substring(j, j + wordLen);
// If the word is one of the target words (exists in the words array)
if (wordMap.containsKey(word)) {
// Add the word to the count in the current window
curMap.put(word, curMap.getOrDefault(word, 0) + 1);
count++; // Increase the number of matched words
// If the current word appears more than required, shrink the left boundary of the window
// Remove the leftmost word until the count of the current word is within the required limit
while (curMap.get(word) > wordMap.get(word)) {
String leftWord = s.substring(left, left + wordLen);
curMap.put(leftWord, curMap.get(leftWord) - 1);
count--;
left += wordLen;
}
// If all words are found (matching the required count)
if (count == wordCount) {
result.add(left); // Add the current valid starting index to the result
// Remove the leftmost word and continue searching for the next match
// This allows finding all possible matching positions
String leftWord = s.substring(left, left + wordLen);
curMap.put(leftWord, curMap.get(leftWord) - 1);
count--;
left += wordLen;
}
} else {
// If a word is encountered that is not in the target word list
// Reset all states and start matching from the next position
curMap.clear();
count = 0;
left = j + wordLen;
}
}
}
return result;
}
public static void main(String[] args) {
// Test case 1: Basic case
// "barfoo" and "foobar" are valid substrings
String s1 = "barfoothefoobarman";
String[] words1 = {"foo","bar"};
System.out.println("Test Case 1: " + findSubstring(s1, words1)); // Expected output: [0, 9]
// Test case 2: Repeated characters
// Test handling of repeated words
String s2 = "aaaaaaaa";
String[] words2 = {"aa","aa"};
System.out.println("Test Case 2: " + findSubstring(s2, words2));
// Test case 3: No matches
// Test case where no matches are found
String s3 = "wordgoodgoodgoodbestword";
String[] words3 = {"word","good","best","good"};
System.out.println("Test Case 3: " + findSubstring(s3, words3)); // Expected output: []
}
}
Enjoy Reading This Article?
Here are some more articles you might like to read next: