Showing posts with label Algorithms. Show all posts
Showing posts with label Algorithms. Show all posts

Friday, February 6, 2026

Cannibal Characters - You want to minimize the length of the string s (Easy)

Index of "Algorithms: Design and Analysis"
<<< Previous    Next >>>

Try solving on Hacker Earth    Test Cases

Problem

You are given an integer n and a string s of size n composed of lower case english letters. You can perform the following operation on it: In one operation, you have to choose any character in the string s, then delete the first character to the left of the chosen character that is equal to the chosen character (if there exists) and delete the first character to the right of the chosen character that is equal to the chosen character (if there exists). Note that in one operation, the length of the string s is reduced by a maximum of two characters. Task You want to minimize the length of the string s. Find the minimum number of operations that need to be performed to minimize the length of the string s. Note: Assume 1 based indexing. Example Assumptions : n = 4 s = "abaa" (without quotes) Approach: Choose 3rd character in the string for 1st operation, this will delete the 1st character and 4th character in string s, the string becomes "ba". The length of the string s can not be reduced further. Hence, minimum number of operations needed to reduce the length of the string s to a minimum is 1. Function Description Complete the Minimum_Operations function provided in the editor. This function takes the following 2 parameters and returns the required answer: n: Represents the length of string s. s: Represents the string s. Input format Note: This is the input format that you must use to provide custom input (available above the Compile and Test button). The first line contains a single integer T, which denotes the number of test cases. T also specifies the number of times you have to run the Minimum_Operations function on a different set of inputs. For each test case: First line contains an integer n. Second line contains a string s. Output format For each test case in a new line, print the minimum number of operations required to minimize the length of string s. Constraints

Brainstorming... Initial Thoughts

The problem is asking us to find the minimum number of operations required to minimize the length of a given string s. The operation involves choosing a character in the string and deleting the first occurrence of that character to the left and right of the chosen character. To solve this problem, we can iterate through the string and count the occurrences of each character. We can then determine how many operations are needed to remove all occurrences of each character. The total number of operations will be the sum of the operations needed for each character. If number of occurrences of a character is n: we need n // 2 operations to remove n-1 occurrences of that character. Finally, we can sum up the operations needed for all characters to get the total minimum number of operations required to minimize the length of the string s.

Code Implementation

from collections import Counter def Minimum_Operations (n, s): # Write your code here occ = Counter(s) chars = set(list(s)) num_ops = 0 for c in chars: if occ.get(c, 0) > 1: num_ops += occ.get(c, 0) // 2 return num_ops T = int(input()) for _ in range(T): n = int(input()) s = input() out_ = Minimum_Operations(n, s) print (out_)

Count the number of occurrences of k in S (Super Easy)

Index of "Algorithms: Design and Analysis"
<<< Previous    Next >>>

Try solving on Hacker Earth

def solve (S, k):
    # Write your code here
    return S.count(k)

T = int(input())
for _ in range(T):
    S = input()
    k = input()

    out_ = solve(S, k)
    print (out_)

Thursday, February 5, 2026

ASME to SAME - Can you convert s into t (Easy)

Index of "Algorithms: Design and Analysis"

Attempt it on HackerEarth
You are given 2 strings s and t both containing only lowercase English characters with s containing some ? as well. You can swap characters at positions i and j in the string s (j > i) any number of times and can also replace any ? with any lowercase English character. Can you convert s into t ?

Input Format

The first line contains an integer T denoting the number of test cases. 

The first line of each test case contains an integer N, the length of the strings.

The second line of each test case contains N lowercase English characters with some ? (possibly 0) denoting string s.

The third line of each test case contains N lowercase English characters denoting string t.

Output Format

For each test case, print 'Yes' (without quotation marks) if it is possible to convert s into t. Otherwise, print 'No' (without quotation marks). Print the output in a new line.

Constraints

1 <= T <= 100
1 <= N <= 10**5

Sample Input

3
4
???n
aman
4
aacb
aabc
3
?po
oyo

Sample Output

Yes
Yes
No

Time Limit: 2
Memory Limit: 256
Source Limit:

Explanation

In the first sample, we can replace first 3 with characters a, m, a respectively to obtain the final string.

In the second sample, we can swap 3rd and 4th characters to get our final string.

In the third testcase, no matter what we do, we cannot convert s into t.


Initial Thoughts

1. The problem requires checking if we can transform string s into string t by swapping characters and replacing '?' characters.
2. Since we can swap characters freely, the order of characters in s does not matter.
3. We need to ensure that for every character in t, there are enough corresponding characters in s or '?' characters to replace.
4. We can use frequency counts to compare the characters in both strings.
5. If the count of any character in t exceeds the count in s plus the number of '?' characters, then the transformation is not possible.
6. Otherwise, it is possible to transform s into t.
7. We also need to check if there is some character in t that is not present in s (and otherwise: in s that is not in t) at all and there are no '?' characters in s to replace it with.


My Code

from collections import Counter

def can_convert(s, t):
    if len(s) != len(t):
        return "No"
    count_s = Counter(s)
    count_t = Counter(t)

    wildcards_s = count_s.get('?', 0)

    for char in count_t:
        if count_t[char] > count_s.get(char, 0):
            needed = count_t[char] - count_s.get(char, 0)
            wildcards_s -= needed
            if wildcards_s < 0:
                return "No"
        elif count_s.get(char, 0) > count_t[char]:
            return "No"
    return "Yes"

    

T = int(input())
for _ in range(T):
    N = int(input())
    s = input().strip()
    t = input().strip()
    print(can_convert(s, t))


Note: I have tested my code. And ChatGPT's code (below) is not tested for correctness, mistakes or hallucinations.
Download Test Cases


ChatGPT's Thoughts

Me: Explain the solution to this problem in layman terms. Give clear descriptions of what this problem is trying to teach/assess, what design pattern, what problem solving trick/technique.

Let’s explain this from first principles, in a way that a layman (or an early learner) can follow, and then connect it to what the problem is testing and the underlying technique.


🧩 Problem restated in simple words

You are given two strings of the same length:

  • s → may contain lowercase letters and ?

  • t → contains only lowercase letters

You are allowed to:

  1. Swap any two characters in s (as many times as you want)

  2. Replace each ? in s with any lowercase letter

Your task:
👉 Decide whether it is possible to transform s into t.

You don’t need to show how, just say Yes or No.


🧠 Key observation (very important)

Since you can:

  • Swap characters freely

  • Replace ? with any letter

👉 The order of characters in s does NOT matter at all.

Only the counts of characters matter.

This turns the problem into a frequency matching problem.


🔍 How to think about it (layman logic)

Think of string s as a bag of letters:

  • Some letters are fixed (a, b, c, …)

  • Some are wildcards (?) that you can turn into anything

String t is another bag of letters.

Your question becomes:

“Can I use the fixed letters + the ? wildcards in s to match exactly the letters in t?”


💡 Step-by-step reasoning

Step 1: Count characters in t

Example:

ini
t = "aman" counts = {a:2, m:1, n:1}

Step 2: Count fixed letters in s and count ?

Example:

ini
s = "???n" fixed = {n:1} wildcards = 3

Step 3: Match fixed letters

For each letter in t:

  • If s already has that letter → use it

  • Otherwise → you must use a ?

If at any point:

  • Required letters > available fixed + ?

❌ Answer is No


Step 4: If all needs are satisfied

✔️ Answer is Yes


🧪 Example walkthrough

Example 1

ini
s = "???n" t = "aman"
  • Fixed in s: n

  • Wildcards: 3

  • Needed in t: a(2), m(1), n(1)

We already have n
Use ?a, m, a

✔️ Possible → Yes


Example 2

ini
s = "aadb" t = "aabc"
  • s fixed: a(2), d(1), b(1)

  • t needs: a(2), b(1), c(1)

We need c but:

  • No ?

  • No c in s

❌ Impossible → No


🎯 What this problem is trying to teach / assess

1️⃣ Abstraction

  • Ignore swaps → reduce problem to counts

2️⃣ Frequency counting

  • A core skill in string problems

3️⃣ Handling wildcards

  • ? acts as a flexible resource

4️⃣ Logical feasibility check

  • “Do I have enough resources to meet the demand?”


🧠 Design pattern used

Greedy + Frequency Matching

  • Greedy: use fixed letters first

  • Use wildcards only when needed

No backtracking. No brute force. No permutations.


🧰 Problem-solving trick / technique

When swaps are unlimited, order doesn’t matter — only counts do.

This trick appears in:

  • Anagram problems

  • String transformation checks

  • Inventory matching problems

  • Resource allocation puzzles


🧠 One-line intuition

“After ignoring order, can the letters (and ?) in s supply the letters required by t?”


🏁 Final takeaway

This is a thinking problem, not a coding-heavy one.

It tests whether you can:

  • Simplify a problem

  • Spot what actually matters

  • Reduce it to a clean frequency check

If you want next:

  • Full Python code

  • Edge cases explained

  • Time/space complexity

  • Why swapping makes order irrelevant (proof)

Just tell me 😊



Me: Full Python code

Here is the complete, clean, and efficient Python solution, followed by a short explanation.


✅ Full Python Code

python
def can_convert(s, t): from collections import Counter count_s = Counter(s) count_t = Counter(t) wildcards = count_s.get('?', 0) # Check each character needed in t for ch in count_t: available = count_s.get(ch, 0) needed = count_t[ch] if available >= needed: continue else: required_from_q = needed - available if required_from_q > wildcards: return "No" wildcards -= required_from_q return "Yes" # ---- Driver code ---- T = int(input()) for _ in range(T): N = int(input()) s = input().strip() t = input().strip() print(can_convert(s, t))

🧠 Explanation (simple & clear)

What the code does

  1. Counts letters in s and t

    • Uses Counter to track how many times each letter appears.

  2. Counts how many ? characters are in s

    • These are wildcards that can become any letter.

  3. For each letter in t

    • First use matching letters already in s

    • If more are needed, try to use ?

    • If not enough ?, conversion is impossible

  4. If all letters are satisfied → print Yes


🧪 Example

ini
s = "???n" t = "aman"
  • Need: a(2), m(1), n(1)

  • Have: n(1) + ?(3)

  • Possible → Yes


⏱️ Time & Space Complexity

MetricComplexity
TimeO(N)
SpaceO(1) (26 letters max)

🎯 What this solution demonstrates

  • Frequency counting

  • Greedy resource usage (? as wildcards)

  • Reduction of problem complexity by ignoring order


🏁 Final takeaway

If swaps are unlimited, order doesn’t matter — only counts do.

If you want:

  • Step-by-step dry run

  • Edge cases

  • Proof of correctness

  • Alternative implementation without Counter

Just ask 😊

Tuesday, February 3, 2026

Rook Attack (Easy) - Find the position where we should place the rook, where Rook has maximum impact

Index of "Algorithms: Design and Analysis"

Try out the problem on Hacker Earth
Rook Attack

Given a N x M chessboard, where every cell has a value assigned to it denoted by 
 (Cell in the ith row from top and jth column from left).

Find the position (x, y) where we should place the rook, just the sum of cells which are under attack of rook is maximum possible. The rook can not attack the cell on which it is placed.

If there are more than one positions for (x, y), return the position where x is as minimum as possible. If there are more than one positions with equal x, return the position where y is as minimum as possible.

Note:

-> 1 based indexing is followed.
-> A rook can attack all the cells which are either in horizontal or vertical direction to the rook's position.
Input

First line contains two space separated integers denoting N and M.

Next N lines contains M space separated integers denoting the values of array A.

Output

Print two space separated integers x and y denoting the rook's position.

Constraints

1 ≤ N, M ≤ 10**6
1 ≤ A[i][j] ≤ 10**4

Sample Input
2 2
4 1 
3 1

Sample Output
1 2

Time Limit: 1.5
Memory Limit: 256
Source Limit:

Explanation

If we place the rook at (1, 2) position, the cells under attack of rook will be
(1, 1), (2, 2)
The sum of these cells will be
4 + 1 = 5, which is maximum possible.



Brute-Force Thinking....

Iterate through each cell of the chessboard and for each cell, calculate the sum of values in its row and column, excluding the value of the cell itself. Keep track of the maximum sum found and the corresponding position. If a new maximum is found, update the position. If the same maximum is found, check for the smallest row and column indices.


My Code:


N, M = map(int, input().split())

A = [list(map(int, input().split())) for _ in range(N)]

rowSum = [0] * N
colSum = [0] * M

for i in range(N):
    for j in range(M):
        rowSum[i] += A[i][j]
        colSum[j] += A[i][j]

best_score = -1
best_row = -1
best_col = -1

for i in range(N):
    for j in range(M):
        score = rowSum[i] + colSum[j] - 2 * A[i][j]

        # print("Score: ", score)
        # print(best_score, best_row, best_col)

        if score > best_score or (score == best_score and (i + 1 < best_row or (i + 1 == best_row and j + 1 < best_col))):
            best_score = score
            best_row = i + 1
            best_col = j + 1

print(best_row, best_col)

BEFORE I GIVE YOU CHATGPT'S THOUGHT: I WOULD LIKE TO TELL YOU THAT CHATGPT MADE A MISTAKE -- SAME MISTAKE REPEATEDLY WHEN TALKING ON A POINT ON MULTIPLE OCCASIONS

You see that when score is computed a cell: the value A[i][j] should be subtracted twice because it is counted in both rowSum and colSum. However, in the code and hints provided by ChatGPT, it is subtracted only once. 

So the correct formula for score should be:
score = rowSum[i] + colSum[j] - 2 * A[i][j

ChatGPT's Thoughts

Explain the solution to this problem in layman terms. Give clear descriptions of what this problem is trying to teach/assess, what design pattern, what problem solving trick/technique.

Let’s break this down slowly, simply, and intuitively, without jumping into code first.


🧩 What is the problem saying (in plain English)?

You are given a chessboard (a grid) where each cell has a number.

You want to place one rook on the board.

A rook:

  • Can attack all cells in the same row

  • Can attack all cells in the same column

  • ❌ Cannot attack the cell it is placed on

Your goal is to:

Choose the cell where placing the rook gives the maximum total sum of attacked cells.

If multiple positions give the same maximum sum:

  1. Choose the smallest row index x

  2. If still tied, choose the smallest column index y


🧠 What does the rook “collect”?

If you place the rook at position (x, y):

  • It collects all values in row x

  • Plus all values in column y

  • Minus A[x][y] (because it cannot attack its own cell)

So effectively:

score(x, y) = rowSum[x] + colSum[y] - A[x][y]

🧪 Sample intuition

Input:

4 1 3 1

Grid:

4 1 3 1

At position (1,2):

  • Row 1 sum = 4 + 1 = 5

  • Column 2 sum = 1 + 1 = 2

  • Subtract cell (1,2) = 1

Final score = 5 + 2 - 1 = 6

This is the maximum possible → answer is (1,2)


🚀 The naïve (slow) way — and why it fails

A beginner might think:

  • For each cell, scan its entire row and column

  • Add values

That would cost:

mathematica
O(N + M) per cell Total = O(N * M * (N + M))

This is too slow for large grids (up to 10⁶ cells).


💡 The key insight (problem-solving trick)

Instead of recalculating row and column sums again and again, we can:

Step 1: Precompute

  • The sum of every row → rowSum[]

  • The sum of every column → colSum[]

This takes only:

scss
O(N * M)

Step 2: For every cell (x, y)

Compute the score in constant time:

css
rowSum[x] + colSum[y] - A[x][y]

🎯 What this problem is really testing

1️⃣ Precomputation / Caching

  • Don’t repeat work

  • Compute row and column sums once

  • Reuse them

2️⃣ Optimization mindset

  • Replace nested loops with smart preprocessing

  • Turn an expensive operation into O(1)

3️⃣ Grid / Matrix reasoning

  • Understanding how rows and columns interact

  • Applying formulas on 2D data

4️⃣ Tie-breaking logic

  • Careful comparison logic

  • Attention to problem constraints


🧠 Design pattern used

Precomputation + Enumeration

This is a very common competitive-programming pattern:

  1. Precompute useful aggregates (row sums, column sums)

  2. Enumerate all candidates efficiently

  3. Track the best result with tie-breaking rules


📌 Why subtract A[x][y]?

Because:

  • The rook cannot attack the cell it is placed on

  • That cell is included once in the row sum

  • And once in the column sum

  • So we subtract it once


🧠 One-sentence intuition

“For each cell, imagine the rook collects everything in its row and column — so we just need fast access to row and column totals.”


🏁 Final takeaway

This problem teaches you:

  • How to optimize brute-force ideas

  • How to think in terms of precomputation

  • How to handle 2D data efficiently

  • How to apply clean mathematical reasoning to grids

If you want next:

  • Full Python code

  • Dry-run with a larger example

  • How this idea appears in other problems

  • Space/time complexity discussion

Just tell me 😊



Full Python code

Here is the full, correct, and efficient Python solution, followed by a clear explanation of how it works.


✅ Full Python Code

python
def solve(): import sys input = sys.stdin.readline N, M = map(int, input().split()) A = [list(map(int, input().split())) for _ in range(N)] # Step 1: Compute row sums and column sums row_sum = [0] * N col_sum = [0] * M for i in range(N): for j in range(M): row_sum[i] += A[i][j] col_sum[j] += A[i][j] # Step 2: Find the best position max_score = -1 best_x = 1 best_y = 1 for i in range(N): for j in range(M): score = row_sum[i] + col_sum[j] - A[i][j] if (score > max_score or (score == max_score and (i + 1 < best_x or (i + 1 == best_x and j + 1 < best_y)))): max_score = score best_x = i + 1 # convert to 1-based indexing best_y = j + 1 print(best_x, best_y)

🧠 Explanation in Simple Terms

What are we doing?

We want to place a rook on a chessboard-like grid so that the sum of values it can attack (same row + same column) is as large as possible.

The rook:

  • Attacks everything in its row

  • Attacks everything in its column

  • ❌ Does NOT attack the cell it sits on

So for any cell (i, j):

ini
score = rowSum[i] + colSum[j] - A[i][j]

Step-by-step logic

🔹 Step 1: Precompute row and column sums

Instead of re-adding rows and columns repeatedly (which would be slow), we compute:

  • Sum of each row

  • Sum of each column

This makes later calculations very fast.


🔹 Step 2: Try placing the rook at every cell

For every position (i, j):

  • Compute the attack sum using the formula above

  • Keep track of the maximum score found

  • If scores tie:

    • Pick the smaller row index

    • If still tied, pick the smaller column index


⏱️ Time & Space Complexity

MetricComplexity
TimeO(N × M)
SpaceO(N + M)

This is optimal for a grid with up to 1 million cells.


🧩 What this problem teaches

  • Precomputation optimization (don’t repeat work)

  • 2D grid reasoning

  • Greedy comparison with tie-breaking

  • Turning brute force into efficient code


🏁 Final intuition (one line)

“Precompute row and column totals, then test every cell using a constant-time formula.”

If you want:

  • A dry-run example

  • A version using less memory

  • Similar problems to practice

  • Visualization

Just say the word 🙂



I am super excited to see GPT 5.2 make mistakes and hallucinate... so capturing a couple of screenshots below:

Largest Number - Find out the largest possible number which can be built from N after removing exactly K digits (Easy)

Index of "Algorithms: Design and Analysis"

Try out the problem on Hacker Earth
Given an integer N which has D digits. You have to delete exactly K digits in integer N.

Find out the largest possible number which can be built from N after removing exactly K digits.

Input Format:

First line contains two space separated integers: N K
 
Output Format:

Print the largest possible number which can be built from 
 after removing exactly 
 digits.

Constraints:


Sample Input
3412 1
Sample Output
412
Time Limit: 1
Memory Limit: 256
Source Limit:

Explanation

After removing exactly 1 digit, we can make

412
312
342
341

Among, them 412 is the largest possible number.

Solution:

Couple of intuitive questions to ask yourself before jumping to code:
1. What is the power of 10 that will remain from the original number after removing K digits?
   Ans: D - K
2. What is the position and value of the largest digit in the remaining number?
   Ans: The largest digit must be in the first D - K digits of the original number.
   If largest digit is not in the first D - K digits, we go for the second largest digit.

Psuedo Code

Initialize empty stack
For each digit in N:
    While stack not empty AND
          last digit in stack < current digit AND
          deletions remaining:
        pop stack
        decrease K
    push current digit to stack

If deletions still left:
    remove last K digits from stack

Answer = digits in stack joined together

My Code


N, K = map(int, input().split())

digits = list(map(int, str(N)))

stack = []

for digit in digits:
    while K > 0 and stack and stack[-1] < digit:
        stack.pop()
        K -= 1
    stack.append(digit)

# If there are still K digits to remove, remove from the end
while K > 0:
    stack.pop()
    K -= 1

print(''.join(map(str, stack)))


Q: Explain the solution to this problem in layman terms. Give clear descriptions of what this problem is trying to teach/assess, what design pattern, what problem solving trick/technique.

Great problem choice 👍 — this is a classic interview + competitive programming problem, and it teaches an important way of thinking.

I’ll explain this in layman terms, then connect it to what it’s testing, the design pattern, and the core trick.


🔍 Problem in simple words

You are given:

  • A number N (as digits)

  • A number K (how many digits you must delete)

👉 Your task:
Delete exactly K digits from N
without changing the order of the remaining digits,
so that the resulting number is as large as possible.


Example

ini
N = 3412 K = 1

Possible results after deleting 1 digit:

  • Remove 3 → 412

  • Remove 4 → 312

  • Remove 1 → 342

  • Remove 2 → 341

✔️ Largest = 412


🧠 Key constraint that matters

You cannot rearrange digits.
You can only delete digits.

This is what makes the problem non-trivial.


🧩 How to think about it (layman explanation)

Let’s think like a human looking at the number:

“If I can delete some digits, I want big digits to come as early as possible.”

Because:

  • A bigger digit at the left makes the number larger

  • Later digits matter less


💡 Core idea (greedy thinking)

Whenever you see:

  • A smaller digit before a bigger digit

  • AND you still have deletions left

👉 Delete the smaller digit

Why?

Because keeping the bigger digit earlier makes the number larger overall.


Example walk-through

ini
N = 3412 K = 1

Compare adjacent digits:

cpp
3 < 4delete 3

Now:

412

No deletions left → stop

✔️ Correct answer


🧰 Design Pattern Used

✅ Greedy Algorithm

You make the best local choice at every step:

“If removing this digit makes the number bigger, do it now.”

Greedy works here because:

  • Earlier digits dominate the value of the number

  • Once a digit is fixed, future digits can’t compensate for a bad choice


🔄 Implementation Technique

Monotonic Stack

This problem is usually solved using:

  • A stack that keeps digits in decreasing order

  • While:

    • Stack top < current digit

    • AND deletions left

Pop the stack (delete digit).


Why a stack?

It helps you:

  • Look back at previous digits

  • Remove them efficiently

  • Maintain the best possible prefix


✏️ Pseudocode (human-readable)

sql
Initialize empty stack For each digit in N: While stack not empty AND last digit in stack < current digit AND deletions remaining: pop stack decrease K push current digit to stack If deletions still left: remove last K digits from stack Answer = digits in stack joined together

🧪 Edge cases this problem tests

  1. Digits already decreasing

    ini
    N = 9876, K = 298

    → Just remove from the end

  2. Leading zeros

    ini
    N = 1002, K = 1102
  3. K = D
    → Result is empty or 0 (depending on problem definition)


🎯 What this problem is really assessing

SkillTested
Greedy thinking
Stack usage
Digit manipulation
Order preservation
Edge-case handling
Algorithmic intuition

🧠 Big takeaway

To maximize a number, fix the leftmost digits first
by deleting smaller digits when you get the chance.

This idea appears in many problems:

  • Remove K digits

  • Build largest/smallest number

  • Stock span problems

  • Next greater element


🏁 Final one-line summary

This problem teaches you how to:

Use greedy decisions + a stack to build the best possible number while deleting digits without changing order.

If you want next:

  • Full Python code

  • Dry-run with more examples

  • Why greedy is provably correct

  • How this compares to brute force

Just tell me 🙂



Full Python Code From ChatGPT

Here is the clean, correct, interview-ready Python solution using the greedy + monotonic stack approach we discussed.

This works efficiently even for very large N (up to 10¹⁸).


✅ Full Python Code

python
def largest_number_after_k_deletions(N, K): digits = list(str(N)) stack = [] for d in digits: # Remove smaller digits from stack if possible while stack and K > 0 and stack[-1] < d: stack.pop() K -= 1 stack.append(d) # If deletions still remain, remove from the end while K > 0: stack.pop() K -= 1 # Join digits and remove leading zeros if any result = ''.join(stack).lstrip('0') return result if result else "0" # ---- Driver code ---- N, K = map(int, input().split()) print(largest_number_after_k_deletions(N, K))

🧠 Step-by-Step Explanation (Layman Friendly)

🔹 Convert the number into digits

python
digits = list(str(N))

We treat the number as characters so we can remove digits easily.


🔹 Use a stack to build the best number

python
stack = []

The stack keeps digits in descending order, as much as possible.


🔹 Main greedy logic

python
while stack and K > 0 and stack[-1] < d: stack.pop() K -= 1

This means:

  • If the previous digit is smaller than the current digit

  • AND we still have deletions left

  • Remove the smaller digit to make the number bigger


🔹 Handle leftover deletions

python
while K > 0: stack.pop() K -= 1

If digits are already decreasing (like 9876), we remove digits from the end.


🔹 Clean result

python
result = ''.join(stack).lstrip('0')

Removes leading zeros if they appear.


🧪 Example Walkthrough

Input

yaml
3412 1

Stack evolution

StepDigitStackK
13[3]1
24[] → [4]0
31[4,1]0
42[4,1,2]0

✔️ Output: 412


⏱️ Time & Space Complexity

MetricValue
TimeO(D)
SpaceO(D)

Where D = number of digits in N.


🎯 Why this solution is optimal

  • No brute force

  • No recursion

  • No permutations

  • Works for large numbers

  • Industry-standard greedy solution


🧩 What this problem teaches

  • Greedy decision making

  • Monotonic stacks

  • Digit-level manipulation

  • Why earlier digits matter more


If you want next:

  • A brute-force validator

  • Handling K > 3

  • Explanation of why greedy always works

  • Similar problems to practice

Just say 👍



What is the greedy algorithm in 100 words?

A greedy algorithm is a problem-solving approach where, at each step, you make the best immediate (locally optimal) choice with the hope that these choices lead to an overall optimal solution. It does not look ahead or reconsider past decisions. Greedy algorithms work well when a problem has the greedy-choice property, meaning a locally optimal choice is also globally optimal. They are usually simple, fast, and memory-efficient. Common examples include activity selection, coin change (with certain coin systems), shortest path algorithms like Dijkstra, and problems involving monotonic stacks such as removing digits to form the largest number.