a coding

10 阅读8分钟

GetRand

1

// Question: // In this problem, you're asked to implement a data structure that supports the following operations: // put: Add a key-value pair to the dictionary. // delete: Remove a key-value pair from the dictionary. // get: Retrieve the value associated with a given key. // get_rand_val: Return a random value from the dictionary, with each value having a probability proportional to its frequency of occurrence. // For example, given a dictionary {a: 5, b: 5, c: 6, d: 5}, the get_rand_val()function should return: // 5 with a probability of 3/4 // 6 with a probability of 1/4

import java.util.*;

class Solution {

  Map<String, Integer> map;  // <key, value>
  List<String> keyList; // list of keys

  public Solution() {
    map = new HashMap<>();
    keyList = new ArrayList<>();
  }

  public void put(String key, int val) {
    if (!map.containsKey(key)) {
      keyList.add(key);
    }
    map.put(key, val);
  }

  public int get(String key) {
    if (!map.containsKey(key)) {
      return -1;
    }
    return map.get(key);
  }

  public boolean delete(String key) {
    if (!map.containsKey(key)) {
      return false;
    }

    map.remove(key);

    for (int i = 0; i < keyList.size(); i++) {
      if (key.equals(keyList.get(i))) {
        keyList.remove(i);
        break;
      }
    }
    return true;
  }

  public int getRandomVal() {
    return map.get(keyList.get((int) (Math.random() * keyList.size())));
  }

  public static void main(String[] args) {
    Solution sol = new Solution();
    sol.put("a", 1);
    sol.put("b", 2);
    sol.put("c", 3);
    sol.put("d", 2);

    System.out.println("Random: " + sol.getRandomVal());

    sol.put("a", 33);

    System.out.println("Updated a: " + sol.get("a"));

    sol.delete("a");

    System.out.println("Updated a: " + sol.get("a"));

  }
}

2. equal prob

import java.util.*;

// put down to On
class Solution {

  Map<String, Integer> map;  // <key, value>
  List<String> keyList; // list of keys

  Map<Integer, Integer> valFreqMap; // <value, frequency of that value>
  List<Integer> uniqueValList;  // list of unique value

  public Solution() {
    map = new HashMap<>();
    keyList = new ArrayList<>();

    valFreqMap = new HashMap<>();
    uniqueValList = new ArrayList<>();
  }

  public void put(String key, int val) {
    if (!map.containsKey(key)) {
      keyList.add(key);
    } else if (val != map.get(key)) {
      int oldVal = map.get(key);
      valFreqMap.put(oldVal, valFreqMap.get(oldVal) - 1);
      if(valFreqMap.get(oldVal) == 0) {
        for (int i = 0; i < uniqueValList.size(); i++) {
          if (oldVal == uniqueValList.get(i)) {
            uniqueValList.remove(i);
          }
        }
      }
    }

    map.put(key, val);

    valFreqMap.put(val, valFreqMap.getOrDefault(val, 0) + 1);
    if(valFreqMap.get(val) == 1) {
      uniqueValList.add(val);
    }
  }

  public int get(String key) {
    if (!map.containsKey(key)) {
      return -1;
    }
    return map.get(key);
  }

  public boolean delete(String key) {
    if (!map.containsKey(key)) {
      return false;
    }

    int val = map.get(key);

    map.remove(key);

    for (int i = 0; i < keyList.size(); i++) {
      if (key.equals(keyList.get(i))) {
        keyList.remove(i);
        break;
      }
    }


    valFreqMap.put(val, valFreqMap.getOrDefault(val, 0) - 1);
    if(valFreqMap.get(val) == 0) {
      for (int i = 0; i < uniqueValList.size(); i++) {
        if (val == uniqueValList.get(i)) {
          uniqueValList.remove(i);
        }
      }
    }
    return true;
  }

  public int getRandomVal() {
    // return map.get(keyList.get((int) (Math.random() * keyList.size())));
    return uniqueValList.get((int) (Math.random() * uniqueValList.size()));
  }

  public static void main(String[] args) {
    Solution sol = new Solution();
    sol.put("a", 1);
    sol.put("b", 2);
    sol.put("c", 3);
    sol.put("d", 2);

    System.out.println("Random: " + sol.getRandomVal());

    sol.put("a", 33);

    System.out.println("Updated a: " + sol.get("a"));

    sol.delete("a");

    System.out.println("Updated a: " + sol.get("a"));


    // Solution sol = new Solution();
    // sol.put("a", 5);
    // sol.put("b", 5);
    // sol.put("c", 6);
    // sol.put("d", 5);

    // Map<Integer, Integer> count = new HashMap<>();
    // for (int i = 0; i < 10000; i++) {
    //   int val = sol.getRandomVal();
    //   count.put(val, count.getOrDefault(val, 0) + 1);
    // }

    // System.out.println("Random distribution: " + count);
    // // Should be close to {5=5000, 6=5000}

  }
}

3. all O(1)

class Solution {

  Map<String, Integer> map;  // <key, value>
  List<String> keyList; // list of keys

  Map<Integer, Integer> valFreqMap; // <value, frequency of that value>
  List<Integer> uniqueValList;  // list of unique value


  Map<Integer, Integer> valToIndex; // value, index of that val in the unique list
  Map<String, Integer> keyToIndex;  // key -> index in keyList



  public Solution() {
    map = new HashMap<>();
    keyList = new ArrayList<>();

    valFreqMap = new HashMap<>();
    uniqueValList = new ArrayList<>();

    valToIndex = new HashMap<>();
    keyToIndex = new HashMap<>();
  }

  public void put(String key, int val) {
    if (!map.containsKey(key)) {
      keyList.add(key);
      keyToIndex.put(key, keyList.size() - 1);
    } else if (val != map.get(key)) {
      int oldVal = map.get(key);
      valFreqMap.put(oldVal, valFreqMap.get(oldVal) - 1);
      if(valFreqMap.get(oldVal) == 0) {
        removeFromUniqueList(oldVal);
      }
    }

    map.put(key, val);

    valFreqMap.put(val, valFreqMap.getOrDefault(val, 0) + 1);
    if(valFreqMap.get(val) == 1) {
      addToUniqueList(val);
    }
  }

  public int get(String key) {
    if (!map.containsKey(key)) {
      return -1;
    }
    return map.get(key);
  }

  public boolean delete(String key) {
    if (!map.containsKey(key)) {
      return false;
    }

    int val = map.get(key);

    map.remove(key);

    removeFromKeyList(key);


    valFreqMap.put(val, valFreqMap.getOrDefault(val, 0) - 1);
    if(valFreqMap.get(val) == 0) {
      removeFromUniqueList(val);
    }
    return true;
  }

  public int getRandomVal() {
    // return map.get(keyList.get((int) (Math.random() * keyList.size())));
    return uniqueValList.get((int) (Math.random() * uniqueValList.size()));
  }


  private void removeFromUniqueList(int val) {
    int indexToRemove = valToIndex.get(val);
    int last = uniqueValList.get(uniqueValList.size() - 1);

    // Swap val with last element
    uniqueValList.set(indexToRemove, last);
    valToIndex.put(last, indexToRemove);

    // Remove val
    uniqueValList.remove(uniqueValList.size() - 1);
    valToIndex.remove(val);
  }

  private void addToUniqueList(int val) {
    valToIndex.put(val, uniqueValList.size());
    uniqueValList.add(val);
  }

  void removeFromKeyList(String key) {
    int index = keyToIndex.get(key);
    int lastIndex = keyList.size() - 1;
    String lastKey = keyList.get(lastIndex);

    // Step 1: move lastKey to index
    keyList.set(index, lastKey);

    // Step 2: update index of moved key
    keyToIndex.put(lastKey, index);

    // Step 3: remove last element
    keyList.remove(lastIndex);

    // Step 4: remove key from index map
    keyToIndex.remove(key);
  }


  public static void main(String[] args) {
    Solution sol = new Solution();
    sol.put("a", 1);
    sol.put("b", 2);
    sol.put("c", 3);
    sol.put("d", 2);

    System.out.println("Random: " + sol.getRandomVal());

    sol.put("a", 33);

    System.out.println("Updated a: " + sol.get("a"));

    sol.delete("a");

    System.out.println("Updated a: " + sol.get("a"));


    // Solution sol = new Solution();
    // sol.put("a", 5);
    // sol.put("b", 5);
    // sol.put("c", 6);
    // sol.put("d", 5);

    // Map<Integer, Integer> count = new HashMap<>();
    // for (int i = 0; i < 10000; i++) {
    //   int val = sol.getRandomVal();
    //   count.put(val, count.getOrDefault(val, 0) + 1);
    // }

    // System.out.println("Random distribution: " + count);
    // // Should be close to {5=5000, 6=5000}

  }
}

Card game

this is a two player card gamethe game starts with a deck of 52 cards represented as unique integers [1...52] the cards are randomly shuffled and then dealt out to both players evenly.

on each turn: both players turn over their top-most card the player with the higher valued card takes the cards and puts them in their scoring pile (scoring 1 point per card) this continues until all the players have no cards left. the player with the highest score wins.if they have the same number of cards in their win pile, tiebreaker goes to the player with the highest card in their win pile

print out who is the winner + score, loser + score

Be able to play the game with N players. An input to the game will now be a list of strings (of length N) indicating the player names. The deck contains M cards of distinct integers.

It is not guaranteed M % N == 0. If there are leftover cards they should randomly be handed out to remaining players i.e. with 17 cards and 5 people: 2 people get 4 cards and 3 get 3 cards.

For example the input: game(["Joe", "Jill", "Bob"], 5) would be a game between 3 players and 5 cards you should print the name of the player that won the game and scores. and losers and the scores

1

import java.util.*;

class Solution {

  public void play() {
    List<Integer> deck = new ArrayList<>();

    for (int i = 1; i <= 52; i++) {
      deck.add(i);
    }

    Collections.shuffle(deck);

    Queue<Integer> player1Deck = new LinkedList<>();
    Queue<Integer> player2Deck = new LinkedList<>();

    for (int i = 0; i < deck.size(); i++) {
      if (i % 2 == 0) {
        player1Deck.offer(deck.get(i));
      } else {
        player2Deck.offer(deck.get(i));
      }
    }

    List<Integer> player1WinPile = new ArrayList<>();
    List<Integer> player2WinPile = new ArrayList<>();
    
    int player1Score = 0;
    int player2Score = 0;

    while (!player1Deck.isEmpty() && !player2Deck.isEmpty()) {
      int card1 = player1Deck.poll();
      int card2 = player2Deck.poll();

      if (card1 > card2) {
        player1WinPile.add(card1);
        player1WinPile.add(card2);
        player1Score +=2;
      } else {
        player2WinPile.add(card1);
        player2WinPile.add(card2);
        player2Score +=2;
      }
    }
    

    if (player1Score > player2Score || (player1Score == player2Score && Collections.max(player1WinPile) > Collections.max(player2WinPile))) {
      System.out.println("Player one wins. Score: " + player1Score);
    } else if (player1Score < player2Score) {
      System.out.println("Player two wins. Score: " + player2Score);
    }

  }



  public static void main(String[] args) {
    Solution sol = new Solution();
    sol.play();
  }
}

2 m n



import java.util.*;


class Player {
    String name;
    Queue<Integer> cards = new LinkedList<>();
    int score = 0;
    List<Integer> winPile = new ArrayList<>();

    Player(String name) {
      this.name = name;
    }

    void offerCard(int card) {
      cards.offer(card);
    }

    int playCard() {
      return cards.poll();
    }
  }

  class Game {
    List<Player> players;
    int numCards;

    Game(List<String> players, int numCards) {
      List<Player> p = new ArrayList<>();
      for (String s : players) {
        p.add(new Player(s));
      }
      this.players = p;
      this.numCards = numCards;
    }

    void play() {
      // init and shuffle cards
      List<Integer> deck = new ArrayList<>();
      for (int i = 1; i <= numCards; i++) {
        deck.add(i);
      }
      
      Collections.shuffle(deck);

      // deal out cards
      // Collections.shuffle(players);
      for (int i = 0; i < deck.size(); i++) {
        players.get(i % players.size()).offerCard(deck.get(i));// round robin
      }

      // // 1. Deal evenly first
      // int baseCardsPerPlayer = numCards / players.size();
      // int leftover = numCards % players.size();
      // int cardIndex = 0;

      // for (int i = 0; i < baseCardsPerPlayer; i++) {
      //     for (Player player : players) {
      //         player.offerCard(deck.get(cardIndex));
      //         cardIndex++;
      //     }
      // }

      // // 2. Randomly assign leftover cards
      // // a player can get all/get 0
      // Random rand = new Random();
      // for (int i = 0; i < leftover; i++) {
      //     players.get(rand.nextInt(players.size())).offerCard(deck.get(cardIndex));
      //     cardIndex++;
      // }


      // calculate rounds to play
      int maxRounds = players.get(0).cards.size();
      for (int i = 1; i < players.size(); i++) {
        maxRounds = Math.max(maxRounds, players.get(i).cards.size());
      }

      // each round
      for (int i = 0; i < maxRounds; i++) {
        List<Integer> roundCards = new ArrayList<>();
        int roundMax = -1;
        Player roundMaxPlayer = null;

        for (Player player: players) {
          if (!player.cards.isEmpty()) {
            int card = player.playCard();
            roundCards.add(card);

            if (card > roundMax) {
              roundMax = card;
              roundMaxPlayer = player;
            }
          }
        }

        roundMaxPlayer.score += roundCards.size();
        roundMaxPlayer.winPile.addAll(roundCards); // 
      }

      // find winner
      // 1. find player with highest score
      // 2. if multiple player has highest score, find the one with highest card in win plie

      // find max score among all players
      int maxScore = -1;
      for (Player player : players) {
        maxScore = Math.max(maxScore, player.score);
      }


      // get players with that max score
      List<Player> maxScorePlayers = new ArrayList<>();
      for (Player player : players) {
        if (player.score == maxScore) {
          maxScorePlayers.add(player);
        }
      }

      // find winner by checking max val in winPile
      Player winner = null;
      int maxInWinPile = -1;
      for (Player player : maxScorePlayers) {
        int curMax = Collections.max(player.winPile);
        if (curMax > maxInWinPile) {
          winner = player;
          maxInWinPile = curMax;
        }
      }

      System.out.println("Winner: " + winner.name +" score: " + winner.score);
    }
  }


class Solution {

  public static void main(String[] args) {
    List<String> p = new ArrayList<>();
    p.add("Joe");
    p.add("Jill");
    p.add("Bob");
    p.add("Tom");
    p.add("Jack");
    p.add("adf");

    Game game = new Game(p, 123);
    game.play();
  }
}



co-occurence

abc

image.png


import java.util.*;

class Solution {

  public Map<Character, List<Character>> getMostFreqCoOcur(List<String> list) {
    // each character maps to a map of neighbor characters and co-occurrence counts
    // <char, <char,co-occurence>>
    Map<Character, Map<Character, Integer>> graph = new HashMap<>();

    // for each character, stores the maximum co-occurrence count it has with any neighbor
    Map<Character, Integer> maxCount = new HashMap<>();

    // for each string
    for (String str : list) {
      // de-duplicate chars in string, e.g. aaaaabc->abc
      Set<Character> tmp = new HashSet<>();
      for (char c : str.toCharArray()) {
        tmp.add(c);
      }

      // unique chars in each string
      List<Character> chars = new ArrayList<>(tmp);

      for (int i = 0; i < chars.size(); i++) {
        char from = chars.get(i);

        for (int j = i + 1; j < chars.size(); j++) {
          char to = chars.get(j);

          // --- from -> to ---
          if (!graph.containsKey(from)) {
            graph.put(from, new HashMap<>());
          }
          int count = graph.get(from).getOrDefault(to, 0) + 1;
          graph.get(from).put(to, count);

          // --- to -> from (undirected graph) ---
          if (!graph.containsKey(to)) {
            graph.put(to, new HashMap<>());
          }
          int count2 = graph.get(to).getOrDefault(from, 0) + 1;
          graph.get(to).put(from, count2);

          // Update maximum co-occurrence count for both characters
          maxCount.put(from, Math.max(maxCount.getOrDefault(from, 0), count));
          maxCount.put(to, Math.max(maxCount.getOrDefault(to, 0), count2));
        }
      }
    }

    // result
    Map<Character, List<Character>> res = new HashMap<>();

    for (Map.Entry<Character, Map<Character, Integer>> entry : graph.entrySet()) {
      char from = entry.getKey();
      Map<Character, Integer> neighbors = entry.getValue();
      
      // max co-occurence for this char
      int maxCoOccur = maxCount.get(from);

      List<Character> maxCoOccurNeighbors = new ArrayList<>();
      for (Map.Entry<Character, Integer> nEntry : neighbors.entrySet()) {
        char to = nEntry.getKey();
        int occur = nEntry.getValue();

        // add only if count matches max
        if (occur == maxCoOccur) {
          maxCoOccurNeighbors.add(to);
        }
      }
      res.put(from, maxCoOccurNeighbors);
    }    

    return res;
  }

  public static void main(String[] args) {

    Solution sol = new Solution();

    List<String> list = Arrays.asList("abc", "bcd", "cde");

    // duplicate
    // List<String> list = Arrays.asList("aaaaabc", "bcd", "cde");

    Map<Character, List<Character>> res = sol.getMostFreqCoOcur(list);
    System.out.println(res);
  }
}

shopping

pstack

using linkedlist



import java.util.*;


class PStack {

  class Node {
    Node next;
    int val;

    Node(Node next, int val) {
      this.next = next;
      this.val = val;
    }
  }

  int size;
  Node head;

  PStack() {
    this.size = 0;
    this.head = null;
  }

  PStack(Node head, int size) {
    this.head = head;
    this.size = size;
  }

  int size() {
    return this.size;
  }

  int peek() {
    return this.head.val;
  }

  PStack push(int val) {
    Node newHead = new Node(head, val);

    return new PStack(newHead, this.size() + 1);
  }

  PStack pop() {
    Node next = head.next;

    return new PStack(next, this.size() - 1);
  }

  void printStack() {
    Node cur = head;
    while (cur != null) {
      System.out.print(cur.val + "->");
      cur = cur.next;
    }
    System.out.println("");
  }

  PStack reverse() {
    PStack reversedPStack = new PStack();
    PStack original = this;

    while (original.size() > 0) {
      reversedPStack = reversedPStack.push(original.peek());
      original = original.pop();
    }

    return reversedPStack;
  }

  // 4->3->2->1
  PStack reverse2() {
    Node pre = null;
    Node cur = this.head;
    while (cur != null) {
      Node tmp = cur.next;
      cur.next = pre;
      pre = cur;
      cur = tmp;
    }
    return new PStack(pre, this.size);
  }


}

class Solution {

  public static void main(String[] args) {
    PStack ps = new PStack();
    PStack stack1 = ps.push(1);
    PStack stack2 = stack1.push(2);
    PStack stack3 = stack2.push(3);
    PStack stack4 = stack3.push(4);

    stack4.printStack();

    PStack stack5 = stack4.pop();
    System.out.println(stack5.peek());
    System.out.println(stack5.size());
    stack5.printStack();

    // test reverse
    // stack4.reverse().printStack();

    stack4.reverse2().printStack();
    

  }
}

using tree


import java.util.*;


import java.util.ArrayList;
import java.util.List;

class PStack {
    TreeNode curNode;

    class TreeNode {
        final int value;
        final int depth;
        final TreeNode parent;
        final List<TreeNode> children;

        TreeNode(int value, int depth, TreeNode parent) {
            this.value = value;
            this.depth = depth;
            this.parent = parent;
            this.children = new ArrayList<>();
        }
    }

    // Empty stack constructor
    public PStack() {
        this.curNode = null;
    }

    // Private constructor to share new curNode
    private PStack(TreeNode curNode) {
        this.curNode = curNode;
    }

    public int size() {
        return curNode == null ? 0 : curNode.depth + 1;
    }

    public int peek() {
        return curNode.value;
    }

    public PStack push(int val) {
        TreeNode newNode = new TreeNode(val, curNode == null ? 0 : curNode.depth + 1, curNode);
        if (curNode != null) {
            curNode.children.add(newNode);  // not required for stack logic, but allows full tree
        }
        return new PStack(newNode);
    }

    public PStack pop() {
        return new PStack(curNode.parent);
    }

    public PStack reverse() {
        PStack reversed = new PStack();
        TreeNode node = this.curNode;
        while (node != null) {
            reversed = reversed.push(node.value);
            node = node.parent;
        }
        return reversed;
    }

    public void printStack() {
      TreeNode node = curNode;

      while (node != null) {
          System.out.print(node.value + "->");
          node = node.parent;
      }
      System.out.println("");
    }
}


class Solution {

  public static void main(String[] args) {
    PStack ps = new PStack();
    PStack stack1 = ps.push(1);
    PStack stack2 = stack1.push(2);
    PStack stack3 = stack2.push(3);
    PStack stack4 = stack3.push(4);

    stack4.printStack();

    PStack stack5 = stack4.pop();
    System.out.println(stack5.peek());
    System.out.println(stack5.size());
    stack5.printStack();

    // test reverse
    stack4.reverse().printStack();

    // stack4.reverse2().printStack();
    

  }
}

POPUP


import java.util.*;


import java.util.ArrayList;
import java.util.List;




class Solution {
  static class DomNode {
    String id;
    boolean hidden;
    List<DomNode> children;
    DomNode(String id, boolean hidden, List<DomNode> children) {
      this.id = id;
      this.hidden = hidden;
      this.children = children;
    }

    public String toString() {
      return hidden ? "(" + this.id + ")" : this.id;
    }

  }


  static void openPopup(DomNode root) {
    List<DomNode> path = new ArrayList<>();
    findPathToPopup(root, "POPUP", path);

    // un-hide nodes on path, hide all siblings on path
    for (int i = 0; i < path.size() - 1; i++) {
      DomNode cur = path.get(i);
      DomNode next = path.get(i + 1);

      // hide node on path
      cur.hidden = false; 

      for (DomNode child : cur.children) {
        if (child != next) { // exclude node on path
          child.hidden = true;
        }
      }
    }

    // un-hide POPUP
    DomNode popup = path.get(path.size() - 1);
    popup.hidden =false;

  }

  // find path from root to POPUP
  static boolean findPathToPopup(DomNode node, String popup, List<DomNode> path) {
    if (node == null) {
      return false;
    }

    path.add(node);

    if (node.id.equals(popup)) {
      return true;
    }

    for (DomNode child : node.children) {
      if (findPathToPopup(child, popup, path)) {
        return true;
      }
    }

    // backtrack
    path.remove(path.size() - 1);

    return false;
  }

  static void bfs(DomNode root) {
    Queue<DomNode> queue = new LinkedList<>();
    queue.offer(root);

    while (!queue.isEmpty()) {
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            DomNode node = queue.poll();
            System.out.print(node.toString() + ", ");
            for (DomNode c : node.children) {
                queue.offer(c);
            }
        }
        System.out.println("");
    }
}

  public static void main(String[] args) {
     // POPUP node
    DomNode N = new DomNode("N", false, new ArrayList<>());
    DomNode O = new DomNode("O", false, new ArrayList<>());
    DomNode P = new DomNode("P", true, new ArrayList<>());
    List<DomNode> popupChildren = new ArrayList<>();
    popupChildren.add(N);
    popupChildren.add(O);
    popupChildren.add(P);
    DomNode POPUP = new DomNode("POPUP", true, popupChildren);

    DomNode I = new DomNode("I", false, new ArrayList<>());
    DomNode J = new DomNode("J", false, new ArrayList<>());
    DomNode K = new DomNode("K", true, new ArrayList<>());

    List<DomNode> dChildren = new ArrayList<>();
    dChildren.add(POPUP);
    dChildren.add(I);
    dChildren.add(J);
    dChildren.add(K);
    DomNode D = new DomNode("D", false, dChildren);
    DomNode C = new DomNode("C", false, new ArrayList<>());

    DomNode F = new DomNode("F", false, new ArrayList<>());
    DomNode G = new DomNode("G", false, new ArrayList<>());

    List<DomNode> bChildren = new ArrayList<>();
    bChildren.add(F);
    bChildren.add(G);
    DomNode B = new DomNode("B", false, bChildren);

    List<DomNode> rootChildren = new ArrayList<>();
    rootChildren.add(B);
    rootChildren.add(C);
    rootChildren.add(D);

    DomNode root = new DomNode("ROOT", false, rootChildren);

    System.out.println("Before: ");
    bfs(root);

    openPopup(root);

    System.out.println("After: ");
    bfs(root);
    // System.out.println(bfs(root));
    

  }
}

compress decompress

// decmp- O(m + n) 
// m: compressed len
// n: decompressed len
class Solution {

  public String decompress(String string) {
    // ab3c2ef, a3b15c210
    StringBuilder sb = new StringBuilder();
    
    int i = 0;

    while (i < string.length()) {
      char c = string.charAt(i);
      int times = 0;
      i++;

      // calculate repeat times
      while (i < string.length() && Character.isDigit(string.charAt(i))) {
        times = 10 * times + (string.charAt(i) - '0');
        i++;
      }

      if (times == 0) {
        sb.append(c);
      } else {
        for (int t = 0; t < times; t++) {
          sb.append(c); // repeat
        }
      }
    }

    return sb.toString();
  }

  public String decompress2(String string) {
    // ab3c23ef, a3b3c2#23e3fg#33
    StringBuilder sb = new StringBuilder();
    
    int i = 0;

    while (i < string.length()) {
      char c;
      if (string.charAt(i) == '#') {
        c = string.charAt(i + 1); // next is the number
        i++; // 
      } else {
        c = string.charAt(i);
      }

      int times = 0;
      i++;
      // calculate repeat times
      while (i < string.length() && Character.isDigit(string.charAt(i))) {
        times = 10 * times + (string.charAt(i) - '0');
        i++;
      }

      if (times == 0) {
        sb.append(c);
      } else {
        for (int t = 0; t < times; t++) {
          sb.append(c);
        }
      }
    }

    return sb.toString();
  }

  public String compress(String string) {
    // aaabbc -> a3b2c1, abc -> abc
    if (string.length() == 0) {
      return string;
    }

    StringBuilder sb = new StringBuilder();

    int count = 1;
    for (int i = 1; i < string.length(); i++) {
      if (string.charAt(i) == string.charAt(i - 1)) {
        count++;
      } else {
        sb.append(string.charAt(i - 1));
        if (count != 1) {
          sb.append(count);
        }
        count = 1;
      }
    }
    
    // append last char in string
    sb.append(string.charAt(string.length() - 1));
    if (count != 1) {
      sb.append(count);
    }

    return sb.toString();
    // aab -> a2b, still return?
  }

  public String compress2(String string) {
    // aaabbbcc222eeefg
    if (string.length() == 0) {
      return string;
    }

    StringBuilder sb = new StringBuilder();

    int count = 1;
    for (int i = 1; i < string.length(); i++) {
      if (string.charAt(i) == string.charAt(i - 1)) {
        count++;
      } else {
        if (Character.isDigit(string.charAt(i - 1))) {
          sb.append("#");
          sb.append(string.charAt(i - 1));
        } else {
          sb.append(string.charAt(i - 1));
        }
        
        if (count != 1) {
          sb.append(count);
        }
        count = 1;
      }
    }

    // append last char in string
    char lastChar = string.charAt(string.length() - 1);
    if (Character.isDigit(lastChar)) {
      sb.append("#");
      sb.append(lastChar);
    } else {
      sb.append(lastChar);
    }
    
    if (count != 1) {
      sb.append(count);
    }

    return sb.toString();
  }

  
  
  public static void main(String[] args) {
    
    Solution sol = new Solution();
    // System.out.println(sol.compress("aaaabbbbbccccdde"));
    // System.out.println(sol.compress("abc"));
    // System.out.println(sol.compress("a"));
    // System.out.println(sol.compress("abcdddeffg"));


    // System.out.println(sol.decompress("ab3c2ef"));
    // System.out.println(sol.decompress("abc"));
    // System.out.println(sol.decompress("a"));
    // System.out.println(sol.decompress("abc10e"));
    // System.out.println(sol.decompress("a10b18"));

    // System.out.println(sol.compress2("aaabbbcc222eeefg333"));
    // System.out.println(sol.compress2("aaabbbcc234eeefg23"));

    // System.out.println(sol.decompress2("a3b3c2#23e3fg#33"));
    // System.out.println(sol.decompress2("a3b3c2#2#3#4e3fg#2#3"));

    String s = "adf2";

    System.out.println(s.equals(sol.decompress2(sol.compress2(s))));


  }
}