# Best Poker Hand
**Difficulty:** EASY
[External](https://leetcode.com/problems/best-poker-hand)
Canonical: https://scaleengineer.com/dsa/problems/best-poker-hand
**Patterns:** [Counting](https://scaleengineer.com/dsa/patterns/counting)
**Data structures:** Array, Hash Table
---
## Problem
You are given an integer array `ranks` and a character array `suits`. You have `5` cards where the `ith` card has a rank of `ranks[i]` and a suit of `suits[i]`.

The following are the types of **poker hands** you can make from best to worst:

1. `"Flush"`: Five cards of the same suit.
2. `"Three of a Kind"`: Three cards of the same rank.
3. `"Pair"`: Two cards of the same rank.
4. `"High Card"`: Any single card.

Return _a string representing the **best** type of **poker hand** you can make with the given cards._

**Note** that the return values are **case-sensitive**.

**Example 1:**

**Input:** ranks = [13,2,3,1,9], suits = ["a","a","a","a","a"]
**Output:** "Flush"
**Explanation:** The hand with all the cards consists of 5 cards with the same suit, so we have a "Flush".

**Example 2:**

**Input:** ranks = [4,4,2,4,4], suits = ["d","a","a","b","c"]
**Output:** "Three of a Kind"
**Explanation:** The hand with the first, second, and fourth card consists of 3 cards with the same rank, so we have a "Three of a Kind".
Note that we could also make a "Pair" hand but "Three of a Kind" is a better hand.
Also note that other cards could be used to make the "Three of a Kind" hand.

**Example 3:**

**Input:** ranks = [10,10,2,12,9], suits = ["a","b","c","a","d"]
**Output:** "Pair"
**Explanation:** The hand with the first and second card consists of 2 cards with the same rank, so we have a "Pair".
Note that we cannot make a "Flush" or a "Three of a Kind".

**Constraints:**

* `ranks.length == suits.length == 5`
* `1 <= ranks[i] <= 13`
* `'a' <= suits[i] <= 'd'`
* No two cards have the same rank and suit.

# Approaches
## HashMap for Ranks and HashSet for Suits
This approach directly translates the rules into code using standard Java collections. It first checks for a "Flush" by seeing if all suits are the same. A `HashSet` is a natural choice for this; if all 5 suits are added to a set and the final size is 1, it's a flush. If it's not a flush, it then checks for rank-based hands ("Three of a Kind", "Pair"). A `HashMap` is used to count the occurrences of each rank. By iterating through the counts in the map, we can determine if there's a group of 3 or 2. The checks are performed in order of hand strength to ensure the best hand is always returned.
**Time:** O(1) - The number of cards is fixed at 5. All loops run a constant number of times. · **Space:** O(1) - The `HashSet` and `HashMap` will store at most 5 elements, as the input size is fixed.
**Pros:** The code is highly readable and directly maps to the problem's logic.; It's a general approach that would work even if the range of ranks was large or non-contiguous.
**Cons:** `HashMap` and `HashSet` have some performance overhead compared to using arrays, especially for a small, fixed range of integer keys.; This approach may involve multiple passes over the data or data structures, making it slightly less efficient than a single-pass solution.
### Explanation
The logic is broken down into sequential checks based on the hierarchy of poker hands.

1.  **Flush Check:** We use a `HashSet` to efficiently determine if all suits are identical. Adding all five suits to a set will result in a set of size 1 if and only if they are all the same.
2.  **Rank Counting:** If the hand is not a flush, we need to analyze the ranks. A `HashMap` is used to count the frequency of each rank. We iterate through the `ranks` array and store the counts in the map.
3.  **Hand Evaluation:** We then iterate through the frequency counts stored in the map's values. Since we must return the *best* hand, we check for "Three of a Kind" first. If any rank appears 3 or more times, we immediately return. If not, we check for a "Pair". A boolean flag `hasPair` tracks if we've seen any rank appear twice. 
4.  **Final Result:** After checking all rank frequencies, if we found a pair (and not a three of a kind), we return "Pair". If neither of these conditions is met, the hand is a "High Card".

```java
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

class Solution {
    public String bestHand(int[] ranks, char[] suits) {
        // 1. Check for Flush
        Set<Character> suitSet = new HashSet<>();
        for (char suit : suits) {
            suitSet.add(suit);
        }
        if (suitSet.size() == 1) {
            return "Flush";
        }

        // 2. Count Ranks
        Map<Integer, Integer> rankCounts = new HashMap<>();
        for (int rank : ranks) {
            rankCounts.put(rank, rankCounts.getOrDefault(rank, 0) + 1);
        }

        // 3. Check for Three of a Kind or Pair
        boolean hasPair = false;
        for (int count : rankCounts.values()) {
            if (count >= 3) {
                return "Three of a Kind";
            }
            if (count == 2) {
                hasPair = true;
            }
        }

        // 4. Determine Final Hand
        if (hasPair) {
            return "Pair";
        }

        // 5. Default to High Card
        return "High Card";
    }
}
```
### Algorithm
- **Check for Flush:**
  - Create a `HashSet<Character>`.
  - Iterate through the `suits` array and add each suit to the set.
  - If the size of the set is 1, it's a flush. Return `"Flush"`.
- **Count Ranks:**
  - If it's not a flush, create a `HashMap<Integer, Integer>` to store the frequency of each card rank.
  - Iterate through the `ranks` array, and for each rank, update its count in the map.
- **Check for Three of a Kind or Pair:**
  - Initialize a boolean flag, `hasPair`, to `false`.
  - Iterate through the values (counts) of the `HashMap`.
    - If any count is 3 or greater, we have found a "Three of a Kind". Return `"Three of a Kind"`.
    - If any count is 2, we have found a pair. Set `hasPair = true`.
- **Determine Final Hand:**
  - After checking all rank counts, if the `hasPair` flag is `true`, return `"Pair"`.
- **Default to High Card:**
  - If the function has not returned yet, return `"High Card"`.

## Using a Frequency Array for Rank Counting
This approach is an optimization of the first one. Since the card ranks are small integers (1-13), we can replace the `HashMap` with a simple integer array to count rank frequencies. An array of size 14 can act as a direct-access table (or a frequency map), where the index corresponds to the rank. This is generally faster than using a `HashMap` because it avoids the computational overhead of hashing. The check for a flush is also simplified to a direct iteration without needing a `HashSet`. The overall logic of checking for hands in descending order of value remains the same.
**Time:** O(1) - The loops for checking suits, counting ranks, and checking counts all run a small, constant number of times. · **Space:** O(1) - We use a `rankCounts` array of fixed size 14.
**Pros:** More efficient than using a `HashMap` due to direct array access for frequency counting.; Avoids the overhead of `HashSet` for the flush check.; Maintains good readability while being more performant.
**Cons:** The logic is still spread across a few distinct steps or loops, which could be slightly condensed.
### Explanation
This method improves performance by using data structures tailored to the problem's constraints.

1.  **Optimized Flush Check:** Instead of a `HashSet`, we can perform a simple loop. We assume the hand is a flush and iterate from the second card, comparing each suit to the first. If we find any mismatch, we know it's not a flush and can break the check.
2.  **Array for Rank Counting:** Given that ranks are `1 <= ranks[i] <= 13`, a `HashMap` is overkill. An integer array `rankCounts` of size 14 provides a more efficient way to store frequencies. The rank itself serves as the index into the array.
3.  **Hand Evaluation:** The evaluation process is similar to the first approach but operates on the `rankCounts` array. We iterate through the array to find if any rank occurs 3 or more times (for "Three of a Kind") or exactly 2 times (for "Pair").

```java
class Solution {
    public String bestHand(int[] ranks, char[] suits) {
        // 1. Check for Flush
        boolean isFlush = true;
        for (int i = 1; i < suits.length; i++) {
            if (suits[i] != suits[0]) {
                isFlush = false;
                break;
            }
        }
        if (isFlush) {
            return "Flush";
        }

        // 2. Count Ranks with an array
        int[] rankCounts = new int[14];
        for (int rank : ranks) {
            rankCounts[rank]++;
        }

        // 3. Check for Three of a Kind or Pair
        boolean hasPair = false;
        for (int i = 1; i < rankCounts.length; i++) {
            if (rankCounts[i] >= 3) {
                return "Three of a Kind";
            }
            if (rankCounts[i] == 2) {
                hasPair = true;
            }
        }

        // 4. Determine Final Hand
        if (hasPair) {
            return "Pair";
        }

        // 5. Default to High Card
        return "High Card";
    }
}
```
### Algorithm
- **Check for Flush:**
  - Iterate from the second card (`i=1`) and compare its suit with the first card's suit (`suits[0]`).
  - If any suit is different, it's not a flush. If the loop completes, it is a flush. Return `"Flush"`.
- **Count Ranks with an Array:**
  - If not a flush, create an integer array, `rankCounts`, of size 14, initialized to zeros.
  - Iterate through the `ranks` array. For each `rank`, increment the count at `rankCounts[rank]`.
- **Check for Three of a Kind or Pair:**
  - Initialize a boolean flag, `hasPair`, to `false`.
  - Iterate through the `rankCounts` array (from index 1 to 13).
    - If `rankCounts[i] >= 3`, return `"Three of a Kind"`.
    - If `rankCounts[i] == 2`, set `hasPair = true`.
- **Determine Final Hand:**
  - After the loop, if `hasPair` is `true`, return `"Pair"`.
- **Default to High Card:**
  - If no other hand was found, return `"High Card"`.

## Optimized Single-Pass Logic with Early Exit
This is the most streamlined approach. It prioritizes the highest-ranking hand, "Flush," with a quick check for an early exit. If the hand is not a flush, it proceeds to analyze the ranks in a highly efficient manner. We can count the rank frequencies and find the maximum frequency in a single pass over the `ranks` array. Based on this maximum frequency (e.g., 3 for "Three of a Kind", 2 for "Pair"), we can immediately determine the hand type. This avoids redundant checks and combines data gathering and analysis.
**Time:** O(1) - The input size is constant. We iterate through the suits once and the ranks once. · **Space:** O(1) - Uses a `HashSet` (max 4 elements) and a fixed-size array (14 elements).
**Pros:** Most concise and efficient implementation for this problem.; Combines rank counting and finding the maximum frequency in a single loop, reducing operations.; Clear separation of concerns: flush check is handled first, followed by a single phase for rank analysis.
**Cons:** While efficient, the logic of tracking max frequency during the counting loop might be slightly less direct for a beginner compared to a separate analysis loop.
### Explanation
This approach refines the logic to be as concise and efficient as possible.

1.  **Prioritize Flush Check:** The check for "Flush" is performed first. As it's the highest-value hand, if it exists, no other checks are necessary. A `HashSet` provides a clean way to do this.
2.  **Combined Rank Analysis:** If the hand isn't a flush, we analyze the ranks. Instead of counting first and then iterating again to find the hand type, we can determine the maximum frequency of any rank *while* we are counting. A variable `maxFreq` is maintained and updated inside the same loop that populates the `rankCounts` array.
3.  **Final Decision:** After a single loop through the ranks, the `maxFreq` variable holds all the information we need. If `maxFreq` is 3 (or more, though not possible with 5 cards without a flush), we have a "Three of a Kind". If it's 2, we have a "Pair". If it's 1, it's a "High Card". This simple check on `maxFreq` replaces the need for flags or further loops.

```java
import java.util.HashSet;
import java.util.Set;

class Solution {
    public String bestHand(int[] ranks, char[] suits) {
        // 1. Flush Check
        Set<Character> suitSet = new HashSet<>();
        for (char s : suits) {
            suitSet.add(s);
        }
        if (suitSet.size() == 1) {
            return "Flush";
        }

        // 2. Rank Analysis
        int[] rankCounts = new int[14];
        int maxFreq = 0;
        for (int r : ranks) {
            rankCounts[r]++;
            maxFreq = Math.max(maxFreq, rankCounts[r]);
        }

        // 3. Determine Hand from Max Frequency
        if (maxFreq >= 3) {
            return "Three of a Kind";
        }
        if (maxFreq == 2) {
            return "Pair";
        }
        
        return "High Card";
    }
}
```
### Algorithm
- **Flush Check (Early Exit):**
  - Use a `HashSet` to check if all suits are the same. If its size is 1 after adding all suits, return `"Flush"`.
- **Rank Analysis in a Single Pass:**
  - If not a flush, create a `rankCounts` array of size 14.
  - Initialize `maxFreq = 0`.
  - Iterate through the `ranks` array once:
    - For each rank `r`, increment `rankCounts[r]`.
    - Update `maxFreq = Math.max(maxFreq, rankCounts[r])`.
- **Determine Hand from Max Frequency:**
  - After the loop, check the value of `maxFreq`:
    - If `maxFreq >= 3`, return `"Three of a Kind"`.
    - If `maxFreq == 2`, return `"Pair"`.
    - Otherwise, return `"High Card"`.

# Solutions
### Java

```java
class Solution {
public
  String bestHand(int[] ranks, char[] suits) {
    boolean flush = true;
    for (int i = 1; i < 5 && flush; ++i) {
      flush = suits[i] == suits[i - 1];
    }
    if (flush) {
      return "Flush";
    }
    int[] cnt = new int[14];
    boolean pair = false;
    for (int x : ranks) {
      if (++cnt[x] == 3) {
        return "Three of a Kind";
      }
      pair = pair || cnt[x] == 2;
    }
    return pair ? "Pair" : "High Card";
  }
}

```

### CPP

```cpp
class Solution {
public:
  string bestHand(vector<int> &ranks, vector<char> &suits) {
    bool flush = true;
    for (int i = 1; i < 5 && flush; ++i) {
      flush = suits[i] == suits[i - 1];
    }
    if (flush) {
      return "Flush";
    }
    int cnt[14]{};
    bool pair = false;
    for (int &x : ranks) {
      if (++cnt[x] == 3) {
        return "Three of a Kind";
      }
      pair |= cnt[x] == 2;
    }
    return pair ? "Pair" : "High Card";
  }
};

```

### Python

```python
class Solution:
    # if len(set(suits)) == 1: if all ( a == b for a , b in pairwise ( suits )): return 'Flush' cnt = Counter ( ranks ) if any ( v >= 3 for v in cnt . values ()): return 'Three of a Kind' if any ( v == 2 for v in cnt . values ()): return 'Pair' return 'High Card'
    def bestHand(self, ranks: List[int], suits: List[str]) -> str:

```
