In [2]:
import math
import logging
import random
logging.basicConfig()
log = logging.getLogger('leetcode')

In [1]:
class Solution:
    def combine(self, n, k):
        L = []
        self.go(1, n, k, [], L)
        return L
    
    def go(self, st, n, k, l, L):
        for i in range(st, n - k + 2):
            l0 = [*l, i]
            if k == 1:
                L.append(l0)
            else:
                self.go(i+1, n, k-1, l0, L)
                
    def superPow(self, a, b):
        sum([1,2])

In [29]:
def power_loop(mod, n=None):
    lmap = {}
    
    def make_unique_set(mod, i):
        s, i1 = set(), i
        while i1 not in s:
            s.add(i1)
            i1 = (i1 * i) % mod
        lmap[i] = s
    
    if n is None:
        for i in range(2, mod):
            make_unique_set(mod, i)
    else:
        make_unique_set(mod, n)
    return lmap

In [38]:
sm = power_loop(1337, 2)
# len(sm[2])
# 1336 / 285, 1336 % 285
sm


Out[38]:
{2: {1,
  2,
  4,
  8,
  9,
  15,
  16,
  18,
  23,
  25,
  30,
  32,
  36,
  39,
  43,
  46,
  50,
  51,
  60,
  64,
  65,
  67,
  72,
  78,
  79,
  81,
  85,
  86,
  92,
  100,
  102,
  107,
  109,
  120,
  121,
  128,
  130,
  134,
  135,
  144,
  149,
  156,
  158,
  162,
  163,
  169,
  170,
  172,
  177,
  184,
  193,
  197,
  200,
  204,
  207,
  211,
  214,
  218,
  221,
  225,
  239,
  240,
  242,
  256,
  260,
  263,
  268,
  270,
  277,
  281,
  288,
  289,
  291,
  295,
  298,
  309,
  312,
  316,
  319,
  324,
  326,
  338,
  340,
  344,
  345,
  347,
  351,
  354,
  361,
  368,
  375,
  386,
  387,
  394,
  400,
  407,
  408,
  414,
  421,
  422,
  428,
  431,
  436,
  442,
  449,
  450,
  457,
  459,
  463,
  478,
  480,
  484,
  485,
  491,
  499,
  512,
  515,
  520,
  526,
  529,
  536,
  540,
  554,
  562,
  575,
  576,
  578,
  582,
  583,
  585,
  589,
  590,
  596,
  597,
  599,
  603,
  613,
  618,
  624,
  625,
  627,
  632,
  638,
  641,
  645,
  648,
  652,
  653,
  659,
  669,
  673,
  676,
  680,
  681,
  688,
  690,
  694,
  701,
  702,
  708,
  709,
  711,
  722,
  723,
  729,
  736,
  743,
  750,
  753,
  757,
  765,
  767,
  772,
  774,
  779,
  781,
  788,
  800,
  807,
  809,
  813,
  814,
  816,
  823,
  828,
  841,
  842,
  844,
  849,
  856,
  862,
  872,
  879,
  884,
  893,
  897,
  898,
  900,
  911,
  914,
  918,
  926,
  933,
  956,
  960,
  961,
  963,
  967,
  968,
  970,
  975,
  981,
  982,
  989,
  991,
  995,
  998,
  1003,
  1005,
  1009,
  1019,
  1023,
  1024,
  1030,
  1033,
  1040,
  1045,
  1047,
  1051,
  1052,
  1058,
  1059,
  1072,
  1073,
  1075,
  1080,
  1089,
  1093,
  1108,
  1115,
  1117,
  1124,
  1135,
  1149,
  1150,
  1152,
  1156,
  1159,
  1163,
  1164,
  1166,
  1170,
  1171,
  1173,
  1178,
  1180,
  1185,
  1191,
  1192,
  1194,
  1198,
  1205,
  1206,
  1213,
  1215,
  1226,
  1227,
  1236,
  1243,
  1248,
  1250,
  1254,
  1255,
  1261,
  1264,
  1271,
  1275,
  1276,
  1282,
  1290,
  1296,
  1299,
  1304,
  1306,
  1318}}

In [40]:
power_loop(13)
115*10 % 285


Out[40]:
10

In [44]:
def superPow(self, a: 'int', b: 'List[int]') -> 'int':

    a = a % 1337
    if a == 1 or a == 0:
        return a
    b.reverse()
    s = powerCycle(a, 1337)
    powmod = len(s)
    tens = powerCycle(10, powmod)
    tenmod = len(tens)

    p = 0
    for i, v in enumerate(b):
        if i == 0:
            pp = v
        else:
            pp = (v * tens[(i-1)%tenmod]) % powmod
        p += pp
    p = p % powmod

    return pow(a, p) % 1337

def powerCycle(a, mod):
    i, cycle = a**2, [a]
    while i != a:
        cycle.append(i)
        i = (i*a) % mod
    return cycle

In [45]:
a = 2139430
b = [2,7,1,6,6,6,3,9,9,3,1,1,7,7,4,4,7,3,4,0,3,5,5,6,5,6,0,9,5,1,2,5,8,3,3,6,9,8,8,0,1,1,3,8,0,9,5,8,2,9,0,6,6,5,4,2,3,5,3,9,8,5,6,7,1,1,5,2,0,5,5,3,6,8,4,7,8,9,7,2,0,9,8,8,4,5,2,7,2,6,8,0,3,6,9,6,8,7,9,0,2,4,3,9,4,7,8,4,8,7,7,0,6,7,9,2,2,1,9,4,9,0,7,5,6,6,1,4,3,2,6,8,8,0,7,3,9,7,9,8,6,6,8,2,4,9,4,8,1,5,5,0,7,2,7,4,0,1,0,6,3,7,4,4,9,3,7,8,0,8,6,6,5,7,0,1,6,6,9,9,3,4,2,1,8,9,7,9,0,9,5,6,6,9,0,7,4,9,6,4,7,4,2,4,1,4,5,0,2,7,9,5,1,1,6,2,1,3,1,3,3,8,9,1,9,9,9,3,0,7,9,8,1,3,2,5,7,0,5,9,7,6,4,0,8,3,2,1,8,3,6,3,3,8,5,2,9,6,5,0,5,6,0,6,9,2,3,6,4,0,7,1,7,4,2,7,9,4,0,7,0,8,1,5,6,8,8,6,6,5,6,1,2,6,9,1,0,3,0,5,3,9,8,2,3,0,1,2,7,1,2,9,0,3,4,8,3,4,4,9,0,2,2,2,0,1,5,3,6,5,8,2,5,8,4,0,9,6,5,8,9,7,7,1,2,3,0,7,8,6,6,8,1,0,2,1,1,7,4,8,5,4,2,2,3,6,4,4,4,9,2,6,8,1,9,2,6,1,9,4,8,7,4,9,9,8,2,1,6,7,1,3,3,3,5,6,1,1,0,8,3,4,4,3,7,3,6,4,5,7,0,5,7,5,6,8,3,8,9,1,7,2,6,1,7,1,7,9,5,0,7,8,6,3,1,4,8,9,0,5,9,0,0,8,7,8,6,3,9,8,4,6,0,1,9,0,4,9,1,9,9,8,9,7,3,3,3,1,2,3,7,3,4,9,3,3,0,0,6,9,0,1,5,2,4,7,2,0,6,3,2,5,3,1,4,6,4,8,0,9,1,9,4,7,8,8,1,8,0,7,9,0,0,7,2,6,4,5,7,0,0,9,7,4,2,1,2,9,9,2,8,1,1,4,0,2,2,1,2,2,1,2,4,3,9,7,0,3,4,7,3,4,6,2,0,0,3,3,9,3,5,9,6,9,4,8,1,8,0,3,3,3,5,7,6,4,6,6,9,0,5,4,7,3,6,7,4,0,0,3,5,6,3,3,5,9,1,8,7,3,1,0,8,7,8,5,3,4,3,5,7,9,1,4,4,8,1,8,0,2,4,7,0,9,0,7,8,3,5,7,7,6,8,5,5,8,2,1,2,8,8,9,9,9,5,3,9,7,4,9,1,0,8,1,9,0,8,9,4,5,6,3,1,6,0,9,4,3,2,7,1,0,8,0,1,4,5,1,3,9,2,4,9,1,5,0,1,5,1,7,0,0,0,3,6,1,4,1,4,8,0,7,8,8,9,2,4,4,5,7,6,7,3,7,0,8,0,4,5,1,1,5,1,4,1,0,5,5,1,1,4,1,0,4,1,9,8,6,5,3,5,1,3,9,1,3,9,1,7,5,4,1,2,6,5,5,8,2,3,9,3,7,2,5,3,3,4,4,1,9,7,9,3,0,0,4,6,9,7,5,6,1,6,1,7,3,6,7,5,9,6,0,8,8,5,4,4,1,8,7,3,7,6,6,8,6,2,4,8,9,9,6,0,8,7,0,1,6,7,9,7,6,9,8,4,7,2,0,8,2,8,1,9,6,7,7,3,1,3,3,0,3,9,3,3,9,3,4,7,2,3,4,8,5,2,5,2,6,5,0,8,5,4,8,2,1,7,7,5,1,2,5,6,3,0,9,2,5,5,1,8,1,8,6,8,2,3,0,9,1,2,7,6,6,7,0,0,5,7,5,8,9,2,4,3,3,5,7,8,0,1,8,3,9,7,1,1,0,3,2,1,6,2,0,4,9,0,4,6,8,1,4,9,4,0,4,9,5,4,9,8,5,0,1,6,7,5,9,7,8,2,9,4,4,9,9,3,1,5,2,1,7,6,1,3,7,7,4,4,1,5,4,8,5,8,4,2,3,4,2,3,8,3,0,2,4,1,7,5,6,9,7,5,8,8,0,7,7,4,3,1]

In [50]:
a = a % 1337
print(a)
s = powerCycle(a, 1337)
len(s)


230
Out[50]:
10

In [6]:
def change(amount, coins):
    if len(coins) == 0: return 1 if amount == 0 else 0
    sc = sorted(coins, reverse=True)
    coin = coins[0]
    return countCoins(amount, coin, coins[1:])

def countCoins(amount, coin, rem):
    num = 0
    for cc in range(amount // coin, -1, -1):
        left = amount - cc*coin
        if left == 0:
            num += 1
        elif len(rem) > 0:
            ncoin = rem[0]
            num += countCoins(left, ncoin, rem[1:])
        else:
            return num

    return num

In [9]:
def changeDynamic(amount, coins):
    sc = sorted(coins, reverse=False)
    combos = [0]*amount
    combos.insert(0, 1)
    for coin in sc:
        for i in range(len(combos)):
            if i >= coin:
                combos[i] += combos[i-coin]
                
    return combos[amount]

In [7]:
change(500, [3,5,7,9,10,11])


Out[7]:
3118287

In [11]:
changeDynamic(500, [3,5,7,9,10,11])


Out[11]:
3118287

In [ ]:
# def pacificAtlantic(matrix):
#     m, n = len(matrix), len(matrix[0])
#     P = [[None]*n for _ in range(m)]
#     for i in range(m):
#         for j in range(n):
#             if P[i][j] is None:
#                 val = matrix[i][j]
#                 decision = None
#                 if i == 0 or j == 0:
#                     decision = True
#                 else:
#                     s = set()
#                     if i < m and matrix[i+1][j] <= val and P[i+1][j] is not False:
#                         if P[i+1][j] is True:
#                             decision = True
#                         else:
#                             s.add([i+1, j])                        
#                     if decision is None matrix[i-1][j] <= val and P[i-1][j] is not False:
#                         if P[i-1][j] is True:
#                             decision = True
#                         else:
#                             s.add([i-1, j])
#                     if j < n and matrix[i][j+1] <= val and P[i][j+1] is not False:
#                         if P[]
#                         s.add([i, j+1])
#                     if i < m and matrix[i+1][j] <= val and P[i+1][j] is not False:
#                         s.add([i+1, j])
            
            
#     return P

In [196]:
class PATree:
    def __init__(self, matrix):
        
        self.m, self.n = len(matrix), len(matrix[0])
        m, n = self.m, self.n
        self.P = [PANode(self, x, y, matrix[y][x]) for y in range(m) for x in range(n)]
        P = self.P
        self.equalNodes = {}
        for node in P:
            r = node.getRight()
            node.compareNodes(r)
            b = node.getBelow()
            node.compareNodes(b)
            
        for node in self.P:
            # assign references
            if node.equalTo is not None:
                end = node
                while end.equalTo is not None:
                    end = end.equalTo
                
                end.nodes.extend(node.nodes)
                node.nodes = end.nodes
                for i in range(len(end.reach)):
                    end.reach[i] = end.reach[i] or node.reach[i]
                node.reach = end.reach
    
        for node in self.P:
            node.canReach(0)
            node.canReach(1)
            
    def __repr__(self):
        return '\n'.join([str(p) for p in self.P])

    def prettyPrint(self):
        strs = [x.flag() for x in self.P]
        
        return '\n'.join([''.join(['{:02d}:'.format(x), *strs[x*self.n:(x+1)*self.n]]) for x in range(self.m)])

class PANode:
    
    def __init__(self, tree, x, y, val):
        self.x, self.y = x, y
        self.nodes = []
        self.val = val
        self.pos = y*tree.n + x
        self.tree = tree
        self.reach = [None, None]
        self.reach[0] = True if x == 0 or y == 0 else None
        self.reach[1] = True if x+1 == tree.n or y+1 == tree.m else None
        self.equalTo = None
        
    def __str__(self):
        return '{}:{}, {} nodes. Can reach both? {}. Equal to: {}'\
            .format(self.pos, self.val, len(self.nodes),
                    sum(self.reach) == 2, self.equalTo.pos if self.equalTo is not None else None)
    
    def __repr__(self):
        return self.__str__()
    
    def addNode(self, node):
        self.nodes.append(node)
        
    def getBelow(self):
        return None if self.y + 1 == self.tree.m else self.tree.P[self.pos+self.tree.n]
    
    def getRight(self):
        return None if self.x + 1 == self.tree.n else self.tree.P[self.pos+1]
    
    def compareNodes(self, other):
        if other is not None and self.pos != other.pos:
            if other.val < self.val:
                self.addNode(other)
            elif self.val < other.val:
                other.addNode(self)
            else:
                end = self
                while other.equalTo is not None:
                    other = other.equalTo
                alreadyEqual = self is other
                while end.equalTo is not None:
                    end = end.equalTo
                    alreadyEqual = alreadyEqual or end is other
                if not alreadyEqual:
                    print('setting', end.pos, 'equal to', other.pos)
                    end.equalTo = other

    def canReach(self, ind):
        if self.reach[ind] is None:
            cr = sum([n.canReach(ind) for n in self.nodes])
            self.reach[ind] = cr > 0
        return self.reach[ind]
    
    
    def reachAll(self):
        return sum(self.reach) == len(self.reach)
    
    def flag(self):
        return '({:02d})'.format(self.val)\
            if self.reachAll()\
            else ' {:02d} '.format(self.val)

In [197]:
testcase = [[1,2,2,3,5],
            [3,2,3,4,4],
            [2,4,5,3,1],
            [6,7,1,4,5],
            [5,1,1,2,4]]

testcase2 = [[1,2,2,3,5],
            [3,2,3,4,4],
            [2,4,5,3,1],
            [6,7,1,4,5]]

testcase3 = [[1,1],
             [1,1]]

tc4 = [[9,10,14,9,2,6,16],
       [0,0,4,5,16,16,15],
       [10,8,16,10,12,8,11],
       [3,13,15,0,19,16,5],
       [13,17,1,12,11,8,14],
       [14,9,11,10,5,19,11],
       [15,3,14,3,9,11,5],
       [9,17,5,15,5,15,7],
       [12,11,10,0,9,14,19],
       [9,1,4,5,8,18,18],
       [1,4,17,16,5,12,18],
       [18,2,0,0,2,11,5],
       [1,15,8,18,13,15,13],
       [11,14,4,13,3,1,1],
       [4,2,11,19,17,8,11],
       [4,11,10,0,1,18,11],
       [11,7,14,4,7,8,9],
       [12,0,0,3,6,2,12],
       [0,16,3,3,5,6,6],
       [6,11,17,12,18,5,15],
       [16,14,8,4,10,16,6],
       [9,7,2,13,5,5,5],
       [14,17,19,4,7,2,5],
       [11,16,18,14,8,10,12],
       [5,11,10,17,2,2,13],
       [7,6,12,3,5,3,12],
       [12,10,0,19,3,15,12],
       [13,2,12,1,1,15,19],
       [11,15,10,8,14,19,8],
       [16,2,2,16,5,15,16],
       [9,8,2,17,15,14,16],
       [17,2,17,17,0,6,3],
       [3,4,13,9,1,4,0],
       [1,3,13,10,14,9,4]]

tc5 = [[11,15,10,8,14,19,8],
       [16,2,2,16,5,15,16],
       [9,8,2,17,15,14,16],
       [17,2,17,17,0,6,3]]

tc6 = [[10,10,10],
       [10,1,10],
       [10,10,10]]

In [188]:
tree = PATree(tc4)
print(tree.prettyPrint())
tree


00: 09  10  14  09  02  06 (16)
01: 00  00  04  05 (16)(16) 15 
02: 10  08  16  10  12  08  11 
03: 03  13  15  00 (19) 16  05 
04: 13  17  01  12  11  08  14 
05: 14  09  11  10  05  19  11 
06: 15  03  14  03  09  11  05 
07: 09  17  05  15  05  15  07 
08: 12  11  10  00  09  14  19 
09: 09  01  04  05  08  18  18 
10: 01  04  17  16  05  12  18 
11: 18  02  00  00  02  11  05 
12: 01  15  08  18  13  15  13 
13: 11  14  04  13  03  01  01 
14: 04  02  11  19  17  08  11 
15: 04  11  10  00  01  18  11 
16: 11  07  14  04  07  08  09 
17: 12  00  00  03  06  02  12 
18: 00  16  03  03  05  06  06 
19: 06  11  17  12  18  05  15 
20: 16  14  08  04  10  16  06 
21: 09  07  02  13  05  05  05 
22: 14  17 (19) 04  07  02  05 
23: 11  16 (18) 14  08  10  12 
24: 05  11  10  17  02  02  13 
25: 07  06  12  03  05  03  12 
26: 12  10  00  19  03  15  12 
27: 13  02  12  01  01  15  19 
28: 11  15  10  08  14  19  08 
29: 16  02  02  16  05  15  16 
30: 09  08  02 (17) 15  14  16 
31:(17) 02 (17)(17) 00  06  03 
32:(03)(04)(13) 09  01  04  00 
33:(01)(03)(13) 10  14  09  04 
Out[188]:
0:9, 1 nodes. Can reach both? False. Equal to: None
1:10, 2 nodes. Can reach both? False. Equal to: None
2:14, 3 nodes. Can reach both? False. Equal to: None
3:9, 2 nodes. Can reach both? False. Equal to: None
4:2, 0 nodes. Can reach both? False. Equal to: None
5:6, 1 nodes. Can reach both? False. Equal to: None
6:16, 2 nodes. Can reach both? True. Equal to: None
7:0, 0 nodes. Can reach both? False. Equal to: 8
8:0, 0 nodes. Can reach both? False. Equal to: None
9:4, 1 nodes. Can reach both? False. Equal to: None
10:5, 1 nodes. Can reach both? False. Equal to: None
11:16, 6 nodes. Can reach both? True. Equal to: 12
12:16, 6 nodes. Can reach both? True. Equal to: None
13:15, 1 nodes. Can reach both? False. Equal to: None
14:10, 3 nodes. Can reach both? False. Equal to: None
15:8, 1 nodes. Can reach both? False. Equal to: None
16:16, 4 nodes. Can reach both? False. Equal to: None
17:10, 2 nodes. Can reach both? False. Equal to: None
18:12, 2 nodes. Can reach both? False. Equal to: None
19:8, 0 nodes. Can reach both? False. Equal to: None
20:11, 2 nodes. Can reach both? False. Equal to: None
21:3, 0 nodes. Can reach both? False. Equal to: None
22:13, 2 nodes. Can reach both? False. Equal to: None
23:15, 3 nodes. Can reach both? False. Equal to: None
24:0, 0 nodes. Can reach both? False. Equal to: None
25:19, 4 nodes. Can reach both? True. Equal to: None
26:16, 3 nodes. Can reach both? False. Equal to: None
27:5, 0 nodes. Can reach both? False. Equal to: None
28:13, 1 nodes. Can reach both? False. Equal to: None
29:17, 4 nodes. Can reach both? False. Equal to: None
30:1, 0 nodes. Can reach both? False. Equal to: None
31:12, 4 nodes. Can reach both? False. Equal to: None
32:11, 2 nodes. Can reach both? False. Equal to: None
33:8, 0 nodes. Can reach both? False. Equal to: None
34:14, 3 nodes. Can reach both? False. Equal to: None
35:14, 2 nodes. Can reach both? False. Equal to: None
36:9, 1 nodes. Can reach both? False. Equal to: None
37:11, 3 nodes. Can reach both? False. Equal to: None
38:10, 2 nodes. Can reach both? False. Equal to: None
39:5, 0 nodes. Can reach both? False. Equal to: None
40:19, 4 nodes. Can reach both? False. Equal to: None
41:11, 1 nodes. Can reach both? False. Equal to: None
42:15, 3 nodes. Can reach both? False. Equal to: None
43:3, 0 nodes. Can reach both? False. Equal to: None
44:14, 4 nodes. Can reach both? False. Equal to: None
45:3, 0 nodes. Can reach both? False. Equal to: None
46:9, 3 nodes. Can reach both? False. Equal to: None
47:11, 2 nodes. Can reach both? False. Equal to: None
48:5, 0 nodes. Can reach both? False. Equal to: None
49:9, 0 nodes. Can reach both? False. Equal to: None
50:17, 4 nodes. Can reach both? False. Equal to: None
51:5, 0 nodes. Can reach both? False. Equal to: None
52:15, 4 nodes. Can reach both? False. Equal to: None
53:5, 0 nodes. Can reach both? False. Equal to: None
54:15, 4 nodes. Can reach both? False. Equal to: None
55:7, 1 nodes. Can reach both? False. Equal to: None
56:12, 3 nodes. Can reach both? False. Equal to: None
57:11, 2 nodes. Can reach both? False. Equal to: None
58:10, 3 nodes. Can reach both? False. Equal to: None
59:0, 0 nodes. Can reach both? False. Equal to: None
60:9, 3 nodes. Can reach both? False. Equal to: None
61:14, 1 nodes. Can reach both? False. Equal to: None
62:19, 3 nodes. Can reach both? False. Equal to: None
63:9, 2 nodes. Can reach both? False. Equal to: None
64:1, 0 nodes. Can reach both? False. Equal to: None
65:4, 1 nodes. Can reach both? False. Equal to: None
66:5, 2 nodes. Can reach both? False. Equal to: None
67:8, 2 nodes. Can reach both? False. Equal to: None
68:18, 5 nodes. Can reach both? False. Equal to: 69
69:18, 5 nodes. Can reach both? False. Equal to: 76
70:1, 0 nodes. Can reach both? False. Equal to: None
71:4, 3 nodes. Can reach both? False. Equal to: None
72:17, 4 nodes. Can reach both? False. Equal to: None
73:16, 3 nodes. Can reach both? False. Equal to: None
74:5, 1 nodes. Can reach both? False. Equal to: None
75:12, 2 nodes. Can reach both? False. Equal to: None
76:18, 5 nodes. Can reach both? False. Equal to: None
77:18, 3 nodes. Can reach both? False. Equal to: None
78:2, 1 nodes. Can reach both? False. Equal to: None
79:0, 0 nodes. Can reach both? False. Equal to: 80
80:0, 0 nodes. Can reach both? False. Equal to: None
81:2, 1 nodes. Can reach both? False. Equal to: None
82:11, 2 nodes. Can reach both? False. Equal to: None
83:5, 0 nodes. Can reach both? False. Equal to: None
84:1, 0 nodes. Can reach both? False. Equal to: None
85:15, 4 nodes. Can reach both? False. Equal to: None
86:8, 2 nodes. Can reach both? False. Equal to: None
87:18, 4 nodes. Can reach both? False. Equal to: None
88:13, 2 nodes. Can reach both? False. Equal to: None
89:15, 4 nodes. Can reach both? False. Equal to: None
90:13, 2 nodes. Can reach both? False. Equal to: None
91:11, 2 nodes. Can reach both? False. Equal to: None
92:14, 3 nodes. Can reach both? False. Equal to: None
93:4, 0 nodes. Can reach both? False. Equal to: None
94:13, 2 nodes. Can reach both? False. Equal to: None
95:3, 1 nodes. Can reach both? False. Equal to: None
96:1, 0 nodes. Can reach both? False. Equal to: 97
97:1, 0 nodes. Can reach both? False. Equal to: None
98:4, 1 nodes. Can reach both? False. Equal to: 105
99:2, 0 nodes. Can reach both? False. Equal to: None
100:11, 3 nodes. Can reach both? False. Equal to: None
101:19, 4 nodes. Can reach both? False. Equal to: None
102:17, 3 nodes. Can reach both? False. Equal to: None
103:8, 1 nodes. Can reach both? False. Equal to: None
104:11, 3 nodes. Can reach both? False. Equal to: 111
105:4, 1 nodes. Can reach both? False. Equal to: None
106:11, 4 nodes. Can reach both? False. Equal to: None
107:10, 1 nodes. Can reach both? False. Equal to: None
108:0, 0 nodes. Can reach both? False. Equal to: None
109:1, 1 nodes. Can reach both? False. Equal to: None
110:18, 4 nodes. Can reach both? False. Equal to: None
111:11, 3 nodes. Can reach both? False. Equal to: None
112:11, 2 nodes. Can reach both? False. Equal to: None
113:7, 1 nodes. Can reach both? False. Equal to: None
114:14, 4 nodes. Can reach both? False. Equal to: None
115:4, 2 nodes. Can reach both? False. Equal to: None
116:7, 3 nodes. Can reach both? False. Equal to: None
117:8, 2 nodes. Can reach both? False. Equal to: None
118:9, 1 nodes. Can reach both? False. Equal to: None
119:12, 3 nodes. Can reach both? False. Equal to: None
120:0, 0 nodes. Can reach both? False. Equal to: 121
121:0, 0 nodes. Can reach both? False. Equal to: None
122:3, 2 nodes. Can reach both? False. Equal to: 129
123:6, 3 nodes. Can reach both? False. Equal to: None
124:2, 0 nodes. Can reach both? False. Equal to: None
125:12, 3 nodes. Can reach both? False. Equal to: None
126:0, 0 nodes. Can reach both? False. Equal to: None
127:16, 4 nodes. Can reach both? False. Equal to: None
128:3, 2 nodes. Can reach both? False. Equal to: 129
129:3, 2 nodes. Can reach both? False. Equal to: None
130:5, 1 nodes. Can reach both? False. Equal to: None
131:6, 3 nodes. Can reach both? False. Equal to: 132
132:6, 3 nodes. Can reach both? False. Equal to: None
133:6, 1 nodes. Can reach both? False. Equal to: None
134:11, 1 nodes. Can reach both? False. Equal to: None
135:17, 4 nodes. Can reach both? False. Equal to: None
136:12, 2 nodes. Can reach both? False. Equal to: None
137:18, 4 nodes. Can reach both? False. Equal to: None
138:5, 0 nodes. Can reach both? False. Equal to: None
139:15, 3 nodes. Can reach both? False. Equal to: None
140:16, 3 nodes. Can reach both? False. Equal to: None
141:14, 3 nodes. Can reach both? False. Equal to: None
142:8, 2 nodes. Can reach both? False. Equal to: None
143:4, 0 nodes. Can reach both? False. Equal to: None
144:10, 2 nodes. Can reach both? False. Equal to: None
145:16, 4 nodes. Can reach both? False. Equal to: None
146:6, 1 nodes. Can reach both? False. Equal to: None
147:9, 1 nodes. Can reach both? False. Equal to: None
148:7, 1 nodes. Can reach both? False. Equal to: None
149:2, 0 nodes. Can reach both? False. Equal to: None
150:13, 4 nodes. Can reach both? False. Equal to: None
151:5, 2 nodes. Can reach both? False. Equal to: 152
152:5, 2 nodes. Can reach both? False. Equal to: 153
153:5, 2 nodes. Can reach both? False. Equal to: 160
154:14, 2 nodes. Can reach both? False. Equal to: None
155:17, 3 nodes. Can reach both? False. Equal to: None
156:19, 4 nodes. Can reach both? True. Equal to: None
157:4, 0 nodes. Can reach both? False. Equal to: None
158:7, 3 nodes. Can reach both? False. Equal to: None
159:2, 0 nodes. Can reach both? False. Equal to: None
160:5, 2 nodes. Can reach both? False. Equal to: None
161:11, 1 nodes. Can reach both? False. Equal to: None
162:16, 2 nodes. Can reach both? False. Equal to: None
163:18, 3 nodes. Can reach both? True. Equal to: None
164:14, 2 nodes. Can reach both? False. Equal to: None
165:8, 2 nodes. Can reach both? False. Equal to: None
166:10, 3 nodes. Can reach both? False. Equal to: None
167:12, 2 nodes. Can reach both? False. Equal to: None
168:5, 0 nodes. Can reach both? False. Equal to: None
169:11, 3 nodes. Can reach both? False. Equal to: None
170:10, 0 nodes. Can reach both? False. Equal to: None
171:17, 4 nodes. Can reach both? False. Equal to: None
172:2, 0 nodes. Can reach both? False. Equal to: 173
173:2, 0 nodes. Can reach both? False. Equal to: None
174:13, 3 nodes. Can reach both? False. Equal to: None
175:7, 2 nodes. Can reach both? False. Equal to: None
176:6, 0 nodes. Can reach both? False. Equal to: None
177:12, 4 nodes. Can reach both? False. Equal to: None
178:3, 0 nodes. Can reach both? False. Equal to: None
179:5, 4 nodes. Can reach both? False. Equal to: None
180:3, 1 nodes. Can reach both? False. Equal to: None
181:12, 1 nodes. Can reach both? False. Equal to: 188
182:12, 2 nodes. Can reach both? False. Equal to: None
183:10, 3 nodes. Can reach both? False. Equal to: None
184:0, 0 nodes. Can reach both? False. Equal to: None
185:19, 4 nodes. Can reach both? False. Equal to: None
186:3, 1 nodes. Can reach both? False. Equal to: None
187:15, 4 nodes. Can reach both? False. Equal to: 194
188:12, 1 nodes. Can reach both? False. Equal to: None
189:13, 3 nodes. Can reach both? False. Equal to: None
190:2, 0 nodes. Can reach both? False. Equal to: None
191:12, 4 nodes. Can reach both? False. Equal to: None
192:1, 0 nodes. Can reach both? False. Equal to: 193
193:1, 0 nodes. Can reach both? False. Equal to: None
194:15, 4 nodes. Can reach both? False. Equal to: None
195:19, 3 nodes. Can reach both? False. Equal to: None
196:11, 0 nodes. Can reach both? False. Equal to: None
197:15, 4 nodes. Can reach both? False. Equal to: None
198:10, 2 nodes. Can reach both? False. Equal to: None
199:8, 1 nodes. Can reach both? False. Equal to: None
200:14, 3 nodes. Can reach both? False. Equal to: None
201:19, 4 nodes. Can reach both? False. Equal to: None
202:8, 0 nodes. Can reach both? False. Equal to: None
203:16, 3 nodes. Can reach both? False. Equal to: None
204:2, 0 nodes. Can reach both? False. Equal to: 205
205:2, 0 nodes. Can reach both? False. Equal to: 212
206:16, 3 nodes. Can reach both? False. Equal to: None
207:5, 0 nodes. Can reach both? False. Equal to: None
208:15, 2 nodes. Can reach both? False. Equal to: None
209:16, 4 nodes. Can reach both? False. Equal to: 216
210:9, 1 nodes. Can reach both? False. Equal to: None
211:8, 3 nodes. Can reach both? False. Equal to: None
212:2, 0 nodes. Can reach both? False. Equal to: None
213:17, 8 nodes. Can reach both? True. Equal to: 220
214:15, 3 nodes. Can reach both? False. Equal to: None
215:14, 1 nodes. Can reach both? False. Equal to: None
216:16, 4 nodes. Can reach both? False. Equal to: None
217:17, 3 nodes. Can reach both? True. Equal to: None
218:2, 0 nodes. Can reach both? False. Equal to: None
219:17, 8 nodes. Can reach both? True. Equal to: 220
220:17, 8 nodes. Can reach both? True. Equal to: None
221:0, 0 nodes. Can reach both? False. Equal to: None
222:6, 3 nodes. Can reach both? False. Equal to: None
223:3, 1 nodes. Can reach both? False. Equal to: None
224:3, 1 nodes. Can reach both? True. Equal to: None
225:4, 3 nodes. Can reach both? True. Equal to: None
226:13, 4 nodes. Can reach both? True. Equal to: 233
227:9, 1 nodes. Can reach both? False. Equal to: None
228:1, 1 nodes. Can reach both? False. Equal to: None
229:4, 2 nodes. Can reach both? False. Equal to: None
230:0, 0 nodes. Can reach both? False. Equal to: None
231:1, 0 nodes. Can reach both? True. Equal to: None
232:3, 1 nodes. Can reach both? True. Equal to: None
233:13, 4 nodes. Can reach both? True. Equal to: None
234:10, 1 nodes. Can reach both? False. Equal to: None
235:14, 3 nodes. Can reach both? False. Equal to: None
236:9, 2 nodes. Can reach both? False. Equal to: None
237:4, 1 nodes. Can reach both? False. Equal to: None

In [191]:
tree = PATree(testcase3)
print(tree.prettyPrint())
tree


00:(01)(01)
01:(01)(01)
Out[191]:
0:1, 0 nodes. Can reach both? True. Equal to: 1
1:1, 0 nodes. Can reach both? True. Equal to: 2
2:1, 0 nodes. Can reach both? True. Equal to: 3
3:1, 0 nodes. Can reach both? True. Equal to: None

In [198]:
tree = PATree(tc6)
print(tree.prettyPrint())
tree


setting 0 equal to 1
setting 1 equal to 3
setting 3 equal to 2
setting 2 equal to 5
setting 5 equal to 6
setting 6 equal to 8
setting 8 equal to 7
00:(10)(10)(10)
01:(10) 01 (10)
02:(10)(10)(10)
Out[198]:
0:10, 4 nodes. Can reach both? True. Equal to: 1
1:10, 4 nodes. Can reach both? True. Equal to: 3
2:10, 4 nodes. Can reach both? True. Equal to: 5
3:10, 4 nodes. Can reach both? True. Equal to: 2
4:1, 0 nodes. Can reach both? False. Equal to: None
5:10, 4 nodes. Can reach both? True. Equal to: 6
6:10, 4 nodes. Can reach both? True. Equal to: 8
7:10, 4 nodes. Can reach both? True. Equal to: None
8:10, 4 nodes. Can reach both? True. Equal to: 7

In [27]:
def medianSortedArrays(nums1=[0], nums2=[], version=2):
    if len(nums1) == 0:
        return median(nums2, -1, len(nums2))
    elif len(nums2) == 0:
        return median(nums1, -1, len(nums1))
    
    vers = {
        1: medianSortedArrays1,
        2: medianSortedArrays2
    }
    return vers[version](nums1, nums2)
    
def medianSortedArrays1(nums1=[0], nums2=[]):
    log.debug('*********')
    log.debug('Arrays: %s, %s', nums1, nums2)
    s1, e1 = -1, len(nums1)
    s2, e2 = -1, len(nums2)
    
    if nums1[-1] <= nums2[0]:
        return median(nums1 + nums2, s1, e1 + e2)
    elif nums2[-1] <= nums1[0]:
        return median(nums2 + nums1, s1, e1 + e2)
    
    while e1 - s1 > 2 and e2 - s2 > 2:
        med1 = median(nums1, s1, e1)
        med2 = median(nums2, s2, e2)
        log.debug('med1: %d, med2: %d', med1, med2)
        if med1 == med2:
            return med1
        jump = min(e1 - s1, e2 - s2)//2
        if med1 < med2:
            e2 -= jump
            s1 += jump
        else:
            e1 -= jump
            s2 += jump
    log.debug('arrived. num1 bounds: [%d, %d], num2 bounds: [%d, %d]',
              s1, e1, s2, e2)
        
    cands1 = getCandidates(nums1, s1, e1)
    cands2 = getCandidates(nums2, s2, e2)
    if len(cands1) == 1 and len(cands2) == 1:
        if nums1[cands1[0]] < nums2[cands2[0]] and\
            cands1[0] < (len(nums1) - 1) and\
            cands2[0] > 0:
            cands1.append(cands1[0] + 1)
            cands2.append(cands2[0] - 1)
        elif nums1[cands1[0]] > nums2[cands2[0]] and\
            cands2[0] < (len(nums2) - 1) and\
            cands1[0] > 0:
            cands1.append(cands1[0] - 1)
            cands2.append(cands2[0] + 1)
            
#     allcands = getCandidates(nums1, s1, e1, nums2, s2, e2)
    allcands = sorted([nums1[i] for i in cands1] + [nums2[i] for i in cands2])
    
    log.debug('all candidates: %s', allcands)
    
    finalval = median(allcands, -1, len(allcands))
    log.debug('final val: %f', finalval)
    return finalval
    
def getCandidates(nums, s, e):
    cands = []
    ms = (s+e)//2
    if (s + e) % 2 == 1:
        me = ms + 1
        if ms >= 0:
            cands.append(ms)
        if me < len(nums):
            cands.append(me)
    else:
        cands.append(ms)
    return cands
    
    
def median(nums, l, r):
    if (l+r) % 2 == 1:
        # odd
        fl = (l+r)//2
        return (nums[fl] + nums[fl+1])/2
    else:
        return nums[(l+r)//2]

Ok so the above approach is getting too complicated. I think I want to try again where instead of two pointers each to the ends of the range, just one pointer each to a point in each list, and then a number which is like the distance of the next jump, which will be cut in half every jump. Initialized to a quarter the length of the smaller list, rounded up.


In [24]:
def medianSortedArrays2(nums1, nums2):
    
    l1, l2 = len(nums1), len(nums2)

In [26]:
log.setLevel(logging.DEBUG)
def test(asrt=False):
    med1 = medianSortedArrays(nums1 = [1, 2], nums2 = [3, 4])
    med2 = medianSortedArrays(nums1 = [1, 4], nums2 = [2])
    med3 = medianSortedArrays(
                [4, 5, 10, 21, 41, 54, 63, 71, 78, 90, 90, 94, 96, 100],
                [4, 10, 17, 26, 30, 31, 36, 48, 48, 58, 59, 62, 75, 77, 81, 88, 93, 94]
    )
    med4 = medianSortedArrays([1,2], [-1,3])
    med5 = medianSortedArrays([1], [2,3,4])
    med6 = medianSortedArrays([2], [1,3,4, 5, 6])
    
    def assertEq(act, exp):
        assert exp == act, "Expected {}, received: {}".format(exp, act)
    
    if asrt:
        assertEq(med1, 2.5)
        assertEq(med2, 2)
        assertEq(med3, 58.5)
        assertEq(med4, 1.5)
        assertEq(med5, 2.5)
        assertEq(med6, 3.5)
        
    for _ in range(5):
        rand1 = sorted([random.randint(0,100) for _ in range(random.randint(10,50))])
        rand2 = sorted([random.randint(0,100) for _ in range(random.randint(10,50))])
        log.debug('random arrays: %s, %s', rand1, rand2)
        medr = medianSortedArrays(rand1, rand2)
        if asrt:
            expmedr = median(sorted(rand1 + rand2), -1, len(rand1) + len(rand2))
            assert medr == expmedr, "Expected {}, got {}".format(expmedr, medr)
            
test(True)


---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-26-19afae912893> in <module>
     31             assert medr == expmedr, "Expected {}, got {}".format(expmedr, medr)
     32 
---> 33 test(True)

<ipython-input-26-19afae912893> in test(asrt)
     15 
     16     if asrt:
---> 17         assertEq(med1, 2.5)
     18         assertEq(med2, 2)
     19         assertEq(med3, 58.5)

<ipython-input-26-19afae912893> in assertEq(act, exp)
     12 
     13     def assertEq(act, exp):
---> 14         assert exp == act, "Expected {}, received: {}".format(exp, act)
     15 
     16     if asrt:

AssertionError: Expected 2.5, received: None

In [17]:
log.setLevel(logging.DEBUG)
# medianSortedArrays([1,2], [-1,3])

medianSortedArrays([1], [2,3,4])


DEBUG:leetcode:*********
DEBUG:leetcode:Arrays: [1], [2, 3, 4]
Out[17]:
2.5

In [20]:
obj = lambda: 0