<p>There is an <strong>undirected</strong> graph consisting of <code>n</code> nodes numbered from <code>1</code> to <code>n</code>. You are given the integer <code>n</code> and a <strong>2D</strong> array <code>edges</code> where <code>edges[i] = [a<sub>i</sub>, b<sub>i</sub>]</code> indicates that there is an edge between nodes <code>a<sub>i</sub></code> and <code>b<sub>i</sub></code>. The graph can be disconnected.</p>

<p>You can add <strong>at most</strong> two additional edges (possibly none) to this graph so that there are no repeated edges and no self-loops.</p>

<p>Return <code>true</code><em> if it is possible to make the degree of each node in the graph even, otherwise return </em><code>false</code><em>.</em></p>

<p>The degree of a node is the number of edges connected to it.</p>

<p>&nbsp;</p>
<p><strong>Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/10/26/agraphdrawio.png" style="width: 500px; height: 190px;" />
<pre>
<strong>Input:</strong> n = 5, edges = [[1,2],[2,3],[3,4],[4,2],[1,4],[2,5]]
<strong>Output:</strong> true
<strong>Explanation:</strong> The above diagram shows a valid way of adding an edge.
Every node in the resulting graph is connected to an even number of edges.
</pre>

<p><strong>Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/10/26/aagraphdrawio.png" style="width: 400px; height: 120px;" />
<pre>
<strong>Input:</strong> n = 4, edges = [[1,2],[3,4]]
<strong>Output:</strong> true
<strong>Explanation:</strong> The above diagram shows a valid way of adding two edges.</pre>

<p><strong>Example 3:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/10/26/aaagraphdrawio.png" style="width: 150px; height: 158px;" />
<pre>
<strong>Input:</strong> n = 4, edges = [[1,2],[1,3],[1,4]]
<strong>Output:</strong> false
<strong>Explanation:</strong> It is not possible to obtain a valid graph with adding at most 2 edges.</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>3 &lt;= n &lt;= 10<sup>5</sup></code></li>
	<li><code>2 &lt;= edges.length &lt;= 10<sup>5</sup></code></li>
	<li><code>edges[i].length == 2</code></li>
	<li><code>1 &lt;= a<sub>i</sub>, b<sub>i</sub> &lt;= n</code></li>
	<li><code>a<sub>i</sub> != b<sub>i</sub></code></li>
	<li>There are no repeated edges.</li>
</ul>

class Solution:
    def isPossible(self, n: int, edges: List[List[int]]) -> bool:
        # constraints: cannot have multiple edges between two nodes
        # cannot have an edge from and to itself
        # adding two edges has multiple possiblities
        # a. 1 - 2
        # b. 1 - 2  3 - 4
        # c. 1 - 2 - 3
        # other possibility 1 = 2 wouldnt make sense
        # case A: if there are two nodes with odd degree and they are not already connected
        # case B: same as case A but for two pairs
        # case C: if there are two nodes with odd degree and they are already connected
        # hence 
        # if two nodes with odd degree
        # -> if not already connected: True
        # -> if already connected but both not connected to a third node: True
        # if four nodes with odd degree
        # -> if can find pairing within constraint: True
        deg = [0] * (n+1)
        adj_list = [set() for _ in range(n+1)]
        for fr, to in edges:
            deg[fr] += 1
            deg[to] += 1
            adj_list[fr].add(to)
            adj_list[to].add(fr)
        odds = list()
        for idx, d in enumerate(deg):
            if d % 2:
                # odd
                odds.append(idx)
        
        if len(odds) == 2:
            first, second = odds
            if second in adj_list[first]:
                # they are already connected, find a third node
                for idx, adj_set in enumerate(adj_list[1:]):
                    if first not in adj_set and second not in adj_set:
                        return True
            else:
                return True
        elif len(odds) == 4:
            # just brute force matching since its only 4
            for i in range(4):
                for j in range(i+1, 4):
                    o = list(range(4))
                    o.pop(j)
                    o.pop(i)
                    k, l = o
                    a, b, c, d = odds[i], odds[j], odds[k], odds[l]
                    if a not in adj_list[b] and c not in adj_list[d]:
                        return True
            return False
        elif not len(odds):
            return True
        else:
            return False
        

61465