From a91a7f6e3dd132351c9535cb0a5193e1f9e1e8f1 Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Wed, 11 Jan 2017 09:37:54 +0800 Subject: [PATCH 1/9] [python2]challenge_10(unreviewed) --- challenge_10/python/shaowen/READE.md | 13 +++++++++ challenge_10/python/shaowen/solution.py | 27 +++++++++++++++++ challenge_10/python/shaowen/unit_test.py | 37 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 challenge_10/python/shaowen/READE.md create mode 100644 challenge_10/python/shaowen/solution.py create mode 100644 challenge_10/python/shaowen/unit_test.py diff --git a/challenge_10/python/shaowen/READE.md b/challenge_10/python/shaowen/READE.md new file mode 100644 index 000000000..6524e58e1 --- /dev/null +++ b/challenge_10/python/shaowen/READE.md @@ -0,0 +1,13 @@ +Valid Closers +======= +Language Version: Python 2.7.12 +------- +1. Approch to Solving the problem + +stack! push and pop + +------- + +2. How to test + +$ python unit_test.py diff --git a/challenge_10/python/shaowen/solution.py b/challenge_10/python/shaowen/solution.py new file mode 100644 index 000000000..265778656 --- /dev/null +++ b/challenge_10/python/shaowen/solution.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Jan 11 09:21:20 2017 + +@author: Shaowen Liu +""" +def solution(strr): + """check if all brackets closed properly""" + + closerof = {'{':'}', '[':']','(':')'} + stack = [] + + for i in list(strr): + # push into stack, if new bracket found + if i in ['[','{','(']: + stack.append(i) + # pop out if proper closer found, else False + elif i in [']','}',')']: + if closerof[stack[-1]] == i: + stack.pop() + elif closerof[stack[-1]] !=i: + return False + # check leftover in stack + if stack: + return False + else: + return True \ No newline at end of file diff --git a/challenge_10/python/shaowen/unit_test.py b/challenge_10/python/shaowen/unit_test.py new file mode 100644 index 000000000..9f04da5bc --- /dev/null +++ b/challenge_10/python/shaowen/unit_test.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Jan 11 09:21:20 2017 + +@author: Shaowen Liu +""" +import unittest +from solution import solution + +class solution_test(unittest.TestCase): + + def test_case1(self): + strr = '{{{}}}' + self.assertEqual(solution(strr), True) + + def test_case2(self): + strr = '{{{{{{{{{adfkjaefia}}}}}}}' + self.assertEqual(solution(strr), False) + + def test_case3(self): + strr = '{{{{{{{{{[[[[[[kadfa{{{{{{{((({daljfdaf({{{[]}}kaldjfs})})))}}}}}}}]]]]]]}kjfela}}}}}}}}' + self.assertEqual(solution(strr), True) + + def test_case4(self): + strr = '{{{[}}}}' + self.assertEqual(solution(strr), False) + + def test_case5(self): + strr = '{{{{{{{{{}}}}}}}}}' + self.assertEqual(solution(strr), True) + + def test_case6(self): + strr = '[[[[[[[[[kafjalfeianfailfeja;fjai;efa;sfj]]]]]]]]]kjajdain' + self.assertEqual(solution(strr), True) + +if __name__ == '__main__': + unittest.main() From f3b32598a331bb387b0a5b894ad3356b2790ebdb Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Wed, 11 Jan 2017 09:43:25 +0800 Subject: [PATCH 2/9] edit readme --- challenge_10/python/shaowen/READE.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/challenge_10/python/shaowen/READE.md b/challenge_10/python/shaowen/READE.md index 6524e58e1..dd34d866a 100644 --- a/challenge_10/python/shaowen/READE.md +++ b/challenge_10/python/shaowen/READE.md @@ -1,13 +1,12 @@ -Valid Closers -======= +##Valid Closers + Language Version: Python 2.7.12 -------- -1. Approch to Solving the problem -stack! push and pop -------- +###Solution + +stack! push and pop -2. How to test +###Testing $ python unit_test.py From 64400d50b52ac72aa8289f9601cdef767f64084b Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Wed, 11 Jan 2017 13:45:23 +0800 Subject: [PATCH 3/9] modified --- challenge_10/python/shaowen/solution.py | 18 ++++++++---------- challenge_10/python/shaowen/unit_test.py | 16 ++++++++++------ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/challenge_10/python/shaowen/solution.py b/challenge_10/python/shaowen/solution.py index 265778656..545b3e3c9 100644 --- a/challenge_10/python/shaowen/solution.py +++ b/challenge_10/python/shaowen/solution.py @@ -1,27 +1,25 @@ # -*- coding: utf-8 -*- """ Created on Wed Jan 11 09:21:20 2017 - -@author: Shaowen Liu """ def solution(strr): """check if all brackets closed properly""" closerof = {'{':'}', '[':']','(':')'} + start = ('[','{','(') + closer = (']','}',')') stack = [] - for i in list(strr): + for i in strr: # push into stack, if new bracket found - if i in ['[','{','(']: + if i in start: stack.append(i) # pop out if proper closer found, else False - elif i in [']','}',')']: + elif i in closer: if closerof[stack[-1]] == i: stack.pop() - elif closerof[stack[-1]] !=i: + else: return False + # check leftover in stack - if stack: - return False - else: - return True \ No newline at end of file + return not stack \ No newline at end of file diff --git a/challenge_10/python/shaowen/unit_test.py b/challenge_10/python/shaowen/unit_test.py index 9f04da5bc..ba792d44f 100644 --- a/challenge_10/python/shaowen/unit_test.py +++ b/challenge_10/python/shaowen/unit_test.py @@ -11,27 +11,31 @@ class solution_test(unittest.TestCase): def test_case1(self): strr = '{{{}}}' - self.assertEqual(solution(strr), True) + self.assertTrue(solution(strr)) def test_case2(self): strr = '{{{{{{{{{adfkjaefia}}}}}}}' - self.assertEqual(solution(strr), False) + self.assertFalse(solution(strr)) def test_case3(self): strr = '{{{{{{{{{[[[[[[kadfa{{{{{{{((({daljfdaf({{{[]}}kaldjfs})})))}}}}}}}]]]]]]}kjfela}}}}}}}}' - self.assertEqual(solution(strr), True) + self.assertTrue(solution(strr)) def test_case4(self): strr = '{{{[}}}}' - self.assertEqual(solution(strr), False) + self.assertFalse(solution(strr)) def test_case5(self): strr = '{{{{{{{{{}}}}}}}}}' - self.assertEqual(solution(strr), True) + self.assertTrue(solution(strr)) def test_case6(self): strr = '[[[[[[[[[kafjalfeianfailfeja;fjai;efa;sfj]]]]]]]]]kjajdain' - self.assertEqual(solution(strr), True) + self.assertTrue(solution(strr)) + + def test_case7(self): + strr = '([{)}]' + self.assertFalse(solution(strr)) if __name__ == '__main__': unittest.main() From 32c7a68c31066d8737f5e756b2b0ebe39acb1ccf Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Wed, 11 Jan 2017 13:59:02 +0800 Subject: [PATCH 4/9] constant begin with capital --- challenge_10/python/shaowen/solution.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/challenge_10/python/shaowen/solution.py b/challenge_10/python/shaowen/solution.py index 545b3e3c9..e7902ef6b 100644 --- a/challenge_10/python/shaowen/solution.py +++ b/challenge_10/python/shaowen/solution.py @@ -6,16 +6,16 @@ def solution(strr): """check if all brackets closed properly""" closerof = {'{':'}', '[':']','(':')'} - start = ('[','{','(') - closer = (']','}',')') + Start = ('[','{','(') + Closer = (']','}',')') stack = [] for i in strr: # push into stack, if new bracket found - if i in start: + if i in Start: stack.append(i) # pop out if proper closer found, else False - elif i in closer: + elif i in Closer: if closerof[stack[-1]] == i: stack.pop() else: From c0d65eeff64998b5bd44d406ddb3ff0552e3d472 Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Thu, 12 Jan 2017 17:12:19 +0800 Subject: [PATCH 5/9] [python2]challenge_[11](Unreviewed) --- challenge_10/python/shaowen/solution.py | 8 +- challenge_11/python/shaowen/READE.md | 41 ++++++ challenge_11/python/shaowen/bst.py | 153 +++++++++++++++++++++++ challenge_11/python/shaowen/unit_test.py | 55 ++++++++ 4 files changed, 253 insertions(+), 4 deletions(-) create mode 100644 challenge_11/python/shaowen/READE.md create mode 100644 challenge_11/python/shaowen/bst.py create mode 100644 challenge_11/python/shaowen/unit_test.py diff --git a/challenge_10/python/shaowen/solution.py b/challenge_10/python/shaowen/solution.py index e7902ef6b..980ab96dd 100644 --- a/challenge_10/python/shaowen/solution.py +++ b/challenge_10/python/shaowen/solution.py @@ -6,16 +6,16 @@ def solution(strr): """check if all brackets closed properly""" closerof = {'{':'}', '[':']','(':')'} - Start = ('[','{','(') - Closer = (']','}',')') + START = ('[','{','(') + CLOSE = (']','}',')') stack = [] for i in strr: # push into stack, if new bracket found - if i in Start: + if i in START: stack.append(i) # pop out if proper closer found, else False - elif i in Closer: + elif i in CLOSE: if closerof[stack[-1]] == i: stack.pop() else: diff --git a/challenge_11/python/shaowen/READE.md b/challenge_11/python/shaowen/READE.md new file mode 100644 index 000000000..71ef061d5 --- /dev/null +++ b/challenge_11/python/shaowen/READE.md @@ -0,0 +1,41 @@ +###Challenge 11 + +Language Version: Python 2.7.12 + + +### Solution + +I did not manipulate bst before, so honestly, I first check the algorithms from the following link, before I implement it in python. I think the illustration is very clear, one could easily get the idea just by going through the graphs. So I would recommend to anyone who is not familiar with the algorithm behind. + +(but java guys should be careful, a java version of implementation is down the page.) + +http://www.algolist.net/Data_structures/Binary_search_tree/Removal + +### How to run +As requested, the program is designed to be interactive, so... +$ python bst.py + +Please type in a list of node integer, seperated by space. + +(now you could type in a list of number just like following to set up the bst) + +5 2 3 12 9 21 19 25 + +Original bst list: + + [5, 2, 3, 12, 9, 21, 19, 25] + +Please type in one node integer you want to delete: + +(now you could type in one integer, please just type in one, not two or more..well, just for test..) + +12 + +New bst list: + +[5, 2, 3, 19, 9, 21, 25] + + +###Testing + +$ python unit_test.py diff --git a/challenge_11/python/shaowen/bst.py b/challenge_11/python/shaowen/bst.py new file mode 100644 index 000000000..e5d16b46c --- /dev/null +++ b/challenge_11/python/shaowen/bst.py @@ -0,0 +1,153 @@ +# -*- coding: utf-8 -*- +# @author: Shaowen Liu + +class Node(): + + def __init__(self, data=None): + self.data = data + self.left = None + self.right = None + + def __str__(self): + return str(self.data) + + def has_child(self): + """return True, if the node has at least one child""" + return self.left or self.right + + def has_one_child(self): + """if the node has only one child, return the child + else, return False + """ + if self.left and (not self.right): + return self.left + elif self.right and (not self.left): + return self.right + else: + return False + +def has_key(root, key): + """lookup node obj in bst, it's possible node is not in bst + but return a 'theory' or 'should-be' path to the node anyway + """ + if not root: return False + + # node found to be root + if key == root.data: + return True + # lookup right branch + elif key > root.data: + return has_key(root.right, key) + # lookup left branch + elif key < root.data: + return has_key(root.left, key) + +def delete_node(root, key): + """delete the node with data = key, from bst starts from root node + args: + root, bst node obj + key, integer + """ + # if root does not have key, return the original bst + if not has_key(root, key): + return root + + if root.data == key: + # if root does not have child, delete the root directly + if not root.has_child(): + return None + # if root has only one child, make that child the root + elif root.has_one_child(): + return root.has_one_child() + # if root has two children, replace the root with the smallest node + # in right branch + else: + min_key = smallest_key(root.right) + root.right = delete_node(root.right, min_key) + root.data = min_key + return root + + # check left branch + if root.left: + root.left = delete_node(root.left, key) + + # check right branch + if root.right: + root.right = delete_node(root.right, key) + + return root + +def insert(root, node): + """insert a new node obj into bst starts from root""" + # if no bst exist, make new node as root + if root is None: + root = node + else: + # add node to the right branch recursively + if node.data >= root.data: + root.right = insert(root.right, node) + # add node to the left branch recersively + else: + root.left = insert(root.left, node) + return root + +def smallest_key(root): + """return the minimum key in bst""" + if root.left: + return smallest_key(root.left) + else: + return root.data + +def build_bst(arr): + """build a bst from an array + args: + arr, a list of integer + """ + root = None + for i in arr: + root = insert(root, Node(i)) + return root + + +def pre_order(root): + """print the tree by pre_order traversal""" + arr = [] + if root: + arr.append(root.data) + arr += pre_order(root.left) + arr += pre_order(root.right) + else: + return arr + return arr + + +if __name__ == '__main__': + #user input + node_arr = raw_input('Please type in a list of node integer, seperated by space.\n') + # insert nodes + root = build_bst(map(int, node_arr.split())) + + # pre_order print + print 'Original bst list: \n %s\n' % str(pre_order(root)) + erase_key = raw_input('Please type in one node integer you want to delete:\n') + + # check whether input is valid + try: + erase_key = int(erase_key) + except ValueError: + raise ValueError('invalid input') + # check if key exists. + if has_key(root, erase_key): + root = delete_node(root, erase_key) + print 'New bst list:\n%s\n' % str(pre_order(root)) + else: + print 'key not found.' + + + + + + + + + \ No newline at end of file diff --git a/challenge_11/python/shaowen/unit_test.py b/challenge_11/python/shaowen/unit_test.py new file mode 100644 index 000000000..737d26f04 --- /dev/null +++ b/challenge_11/python/shaowen/unit_test.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +#@author: Shaowen Liu + + +import unittest +import bst +from bst import Node + +class bst_test(unittest.TestCase): + + # build proper bst list + def test_bst_build_case1(self): + arr = [5, 2, 12, 9, 21, 3, -4, 19, 25] + root = bst.build_bst(arr) + self.assertEqual(bst.pre_order(root), [5, 2, -4, 3, 12, 9, 21, 19, 25]) + + def test_bst_build_case2(self): + arr = [235, 100, 50, 700, 800, 900, 25, 75, 105, 236] + root = bst.build_bst(arr) + self.assertEqual(bst.pre_order(root), [235,100,50,25,75,105,700,236,800,900]) + + + # test for delete method + def test_bst_delete_case1(self): + # delete the leaf node + bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] + root = bst.build_bst(bst_list) + root = bst.delete_node(root,25) + self.assertEqual(bst.pre_order(root), [5, 2, -4, 3, 12, 9, 21, 19]) + + def test_bst_delete_case2(self): + # delete the roof node + bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] + root = bst.build_bst(bst_list) + root = bst.delete_node(root,5) + self.assertEqual(bst.pre_order(root), [9, 2, -4, 3, 12, 21, 19, 25]) + + def test_bst_delete_case3(self): + # delete the node in the middle of the tree + bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] + root = bst.build_bst(bst_list) + root = bst.delete_node(root,2) + self.assertEqual(bst.pre_order(root), [5, 3, -4, 12, 9, 21, 19, 25]) + + def test_bst_delete_case4(self): + # delete the node in the middle of the tree + bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] + root = bst.build_bst(bst_list) + root = bst.delete_node(root,12) + self.assertEqual(bst.pre_order(root), [5, 2, -4, 3, 19, 9, 21, 25]) + + + +if __name__ == '__main__': + unittest.main() From 6a3caa0b62578010d50995c189dabc1f00ae57a2 Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Thu, 12 Jan 2017 18:46:08 +0800 Subject: [PATCH 6/9] fit for multi keys delete --- challenge_11/python/shaowen/READE.md | 21 ++++++---- challenge_11/python/shaowen/bst.py | 57 +++++++++++++++++----------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/challenge_11/python/shaowen/READE.md b/challenge_11/python/shaowen/READE.md index 71ef061d5..7efa324e7 100644 --- a/challenge_11/python/shaowen/READE.md +++ b/challenge_11/python/shaowen/READE.md @@ -5,35 +5,40 @@ Language Version: Python 2.7.12 ### Solution -I did not manipulate bst before, so honestly, I first check the algorithms from the following link, before I implement it in python. I think the illustration is very clear, one could easily get the idea just by going through the graphs. So I would recommend to anyone who is not familiar with the algorithm behind. +As I don't have much exprerience with bst before, so I first check the algorithms from the following link, before I implement it in python. I think the illustration is very clear, one could easily get the idea just by going through the graphs. So I would recommend to anyone who is not familiar with the algorithm behind. (but java guys should be careful, a java version of implementation is down the page.) http://www.algolist.net/Data_structures/Binary_search_tree/Removal ### How to run -As requested, the program is designed to be interactive, so... +As requested, the program is designed to be interactive, so here it is. + $ python bst.py Please type in a list of node integer, seperated by space. (now you could type in a list of number just like following to set up the bst) -5 2 3 12 9 21 19 25 +5 2 1 3 12 9 21 19 36 Original bst list: - [5, 2, 3, 12, 9, 21, 19, 25] +[5, 2, 1, 3, 12, 9, 21, 19, 36] + -Please type in one node integer you want to delete: +Please type in key(s) you want to delete: -(now you could type in one integer, please just type in one, not two or more..well, just for test..) +(now you could type in one int, or a list of int like following, if the key is not in bst, you will also be notified.) -12 +5 7 2 19 + +key 7 not found. New bst list: -[5, 2, 3, 19, 9, 21, 25] +[9, 3, 1, 12, 21, 36] + ###Testing diff --git a/challenge_11/python/shaowen/bst.py b/challenge_11/python/shaowen/bst.py index e5d16b46c..605a84415 100644 --- a/challenge_11/python/shaowen/bst.py +++ b/challenge_11/python/shaowen/bst.py @@ -27,8 +27,8 @@ def has_one_child(self): return False def has_key(root, key): - """lookup node obj in bst, it's possible node is not in bst - but return a 'theory' or 'should-be' path to the node anyway + """lookup key in bst, + return Ture if key found, else False """ if not root: return False @@ -43,15 +43,16 @@ def has_key(root, key): return has_key(root.left, key) def delete_node(root, key): - """delete the node with data = key, from bst starts from root node + """delete the node with data equals to key. args: root, bst node obj - key, integer + key, int """ - # if root does not have key, return the original bst + # if root does not have key, return the root directly if not has_key(root, key): return root + # check root if root.data == key: # if root does not have child, delete the root directly if not root.has_child(): @@ -59,8 +60,9 @@ def delete_node(root, key): # if root has only one child, make that child the root elif root.has_one_child(): return root.has_one_child() - # if root has two children, replace the root with the smallest node - # in right branch + # if root has two children, + # 1. replace the root with the smallest key in right branch + # 2. delete that node with the smallest key else: min_key = smallest_key(root.right) root.right = delete_node(root.right, min_key) @@ -77,22 +79,29 @@ def delete_node(root, key): return root -def insert(root, node): - """insert a new node obj into bst starts from root""" - # if no bst exist, make new node as root +def insert(root, key): + """insert a new node obj into bst + args: + root, node obj + key, int + + """ + new_node = Node(key) + # if bst does not exist, make new node the root if root is None: - root = node + root = new_node else: # add node to the right branch recursively - if node.data >= root.data: - root.right = insert(root.right, node) + if key >= root.data: + root.right = insert(root.right, key) # add node to the left branch recersively else: - root.left = insert(root.left, node) + root.left = insert(root.left, key) return root def smallest_key(root): """return the minimum key in bst""" + if root.left: return smallest_key(root.left) else: @@ -105,7 +114,7 @@ def build_bst(arr): """ root = None for i in arr: - root = insert(root, Node(i)) + root = insert(root, i) return root @@ -129,19 +138,23 @@ def pre_order(root): # pre_order print print 'Original bst list: \n %s\n' % str(pre_order(root)) - erase_key = raw_input('Please type in one node integer you want to delete:\n') + erase_keys = raw_input('Please type in key(s) you want to delete:\n') # check whether input is valid try: - erase_key = int(erase_key) + keys = map(int, erase_keys.split()) except ValueError: raise ValueError('invalid input') + # check if key exists. - if has_key(root, erase_key): - root = delete_node(root, erase_key) - print 'New bst list:\n%s\n' % str(pre_order(root)) - else: - print 'key not found.' + for key in keys: + if has_key(root, key): + root = delete_node(root, key) + #print 'key %s is deleted from bst' % key + else: + print 'key %s not found.' % key + + print 'New bst list:\n%s\n' % str(pre_order(root)) From dfa5620831d271abf07d94cc514422b60e39e607 Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Thu, 12 Jan 2017 18:52:13 +0800 Subject: [PATCH 7/9] delete space --- challenge_11/python/shaowen/bst.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/challenge_11/python/shaowen/bst.py b/challenge_11/python/shaowen/bst.py index 605a84415..fd0be3d7a 100644 --- a/challenge_11/python/shaowen/bst.py +++ b/challenge_11/python/shaowen/bst.py @@ -154,13 +154,4 @@ def pre_order(root): else: print 'key %s not found.' % key - print 'New bst list:\n%s\n' % str(pre_order(root)) - - - - - - - - - \ No newline at end of file + print 'New bst list:\n%s\n' % str(pre_order(root)) \ No newline at end of file From 3547e4ad06cfc82597c72bed1254fde66d241371 Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Fri, 13 Jan 2017 20:45:10 +0800 Subject: [PATCH 8/9] add BST class --- challenge_11/python/shaowen/READE.md | 9 +- challenge_11/python/shaowen/bst.py | 246 +++++++++++++---------- challenge_11/python/shaowen/unit_test.py | 41 ++-- 3 files changed, 161 insertions(+), 135 deletions(-) diff --git a/challenge_11/python/shaowen/READE.md b/challenge_11/python/shaowen/READE.md index 7efa324e7..d8d5a14da 100644 --- a/challenge_11/python/shaowen/READE.md +++ b/challenge_11/python/shaowen/READE.md @@ -5,21 +5,16 @@ Language Version: Python 2.7.12 ### Solution -As I don't have much exprerience with bst before, so I first check the algorithms from the following link, before I implement it in python. I think the illustration is very clear, one could easily get the idea just by going through the graphs. So I would recommend to anyone who is not familiar with the algorithm behind. - -(but java guys should be careful, a java version of implementation is down the page.) +Algorithms ref: http://www.algolist.net/Data_structures/Binary_search_tree/Removal ### How to run -As requested, the program is designed to be interactive, so here it is. $ python bst.py Please type in a list of node integer, seperated by space. -(now you could type in a list of number just like following to set up the bst) - 5 2 1 3 12 9 21 19 36 Original bst list: @@ -29,7 +24,7 @@ Original bst list: Please type in key(s) you want to delete: -(now you could type in one int, or a list of int like following, if the key is not in bst, you will also be notified.) +(you could type in one int, or a list of int like following, if the key is not in bst, you will also be notified.) 5 7 2 19 diff --git a/challenge_11/python/shaowen/bst.py b/challenge_11/python/shaowen/bst.py index fd0be3d7a..440c19dac 100644 --- a/challenge_11/python/shaowen/bst.py +++ b/challenge_11/python/shaowen/bst.py @@ -3,19 +3,19 @@ class Node(): - def __init__(self, data=None): - self.data = data - self.left = None - self.right = None + def __init__(self, key, left=None, right=None, parent=None): + self.key = key + self.left = left + self.right = right + self.parent = parent def __str__(self): - return str(self.data) - - def has_child(self): - """return True, if the node has at least one child""" + return str(self.key) + + def has_any_child(self): return self.left or self.right - def has_one_child(self): + def the_only_child(self): """if the node has only one child, return the child else, return False """ @@ -25,119 +25,152 @@ def has_one_child(self): return self.right else: return False + + def is_left_child(self): + return bool(self.parent.left == self) + + def is_right_child(self): + return bool(self.parent.right == self) -def has_key(root, key): - """lookup key in bst, - return Ture if key found, else False - """ - if not root: return False - - # node found to be root - if key == root.data: - return True - # lookup right branch - elif key > root.data: - return has_key(root.right, key) - # lookup left branch - elif key < root.data: - return has_key(root.left, key) +class BST(): + + def __init__(self, root = None, size = 0): + self.root = root + self.size = size -def delete_node(root, key): - """delete the node with data equals to key. - args: - root, bst node obj - key, int - """ - # if root does not have key, return the root directly - if not has_key(root, key): - return root + def _insert(self, key, current_node): - # check root - if root.data == key: - # if root does not have child, delete the root directly - if not root.has_child(): - return None - # if root has only one child, make that child the root - elif root.has_one_child(): - return root.has_one_child() - # if root has two children, - # 1. replace the root with the smallest key in right branch - # 2. delete that node with the smallest key + if key == current_node.key: + raise IndexError('Find duplicated key.') + elif key > current_node.key: + if current_node.right: + self._insert(key, current_node.right) + else: + current_node.right = Node(key, parent = current_node) + elif key < current_node.key: + if current_node.left: + self._insert(key, current_node.left) + else: + current_node.left = Node(key, parent = current_node) + + def insert(self, key): + """insert new key into bst""" + # if bst does not exist, make new node the root + if not self.root: + self.root = Node(key, parent = None) + # else insert the node into bst recercively else: - min_key = smallest_key(root.right) - root.right = delete_node(root.right, min_key) - root.data = min_key - return root - - # check left branch - if root.left: - root.left = delete_node(root.left, key) + self._insert(key, self.root) + self.size += 1 + + def _has_key(self, key, current_node): - # check right branch - if root.right: - root.right = delete_node(root.right, key) - - return root - -def insert(root, key): - """insert a new node obj into bst - args: - root, node obj - key, int + if key == current_node.key: + return current_node + # lookup right branch + elif key > current_node.key: + return self._has_key(key, current_node.right) + # lookup left branch + elif key < current_node.key: + return self._has_key(key, current_node.left) + + def has_key(self, key): + """lookup key in bst, + return node if key found, else False + """ + if not self.root: + return False + else: + return self._has_key(key, self.root) - """ - new_node = Node(key) - # if bst does not exist, make new node the root - if root is None: - root = new_node - else: - # add node to the right branch recursively - if key >= root.data: - root.right = insert(root.right, key) - # add node to the left branch recersively + def smallest_key(self, current_node): + """start from current_node, + search the node with the minimum key in bst + """ + if not current_node: + raise IndexError('this is an empty (sub)tree') + + if current_node.left: + return self.smallest_key(current_node.left) else: - root.left = insert(root.left, key) - return root + return current_node + + def _delete(self, removed_node): + + # if removed_node has no child + if not removed_node.has_any_child(): + # removed node is a leaf + if removed_node.parent: + if removed_node.is_left_child(): + removed_node.parent.left = None + else: + removed_node.parent.right = None + self.size -= 1 + # removed node is root + else: + self.root = None + self.size = 0 + + # removed node has only one child + elif removed_node.the_only_child(): + if removed_node.parent: + if removed_node.is_left_child(): + removed_node.parent.left = removed_node.the_only_child() + removed_node.the_only_child().parent = removed_node.parent + else: + removed_node.parent.right = removed_node.the_only_child() + removed_node.the_only_child().parent = removed_node.parent + # removed node is root + else: + self.root = self.root.the_only_child() + + # removed node has two children + else: + min_node = self.smallest_key(removed_node.right) + removed_node.key = min_node.key + self._delete(min_node) -def smallest_key(root): - """return the minimum key in bst""" + def delete(self, key): + """delete key from bst""" + removed_node = self.has_key(key) + # if bst has the key, kick off delete process + if removed_node: + self._delete(removed_node) + else: + raise ValueError('key not found.') - if root.left: - return smallest_key(root.left) - else: - return root.data + def _pre_order(self, current_node): + + arr = [] + arr.append(current_node.key) + if current_node.left: + arr += self._pre_order(current_node.left) + if current_node.right: + arr += self._pre_order(current_node.right) + return arr + + def pre_order_print(self): + """print the tree by pre_order traversal""" + if self.root: + return self._pre_order(self.root) + else: + return [] def build_bst(arr): - """build a bst from an array - args: - arr, a list of integer - """ - root = None + """build a bst from an array""" + bst = BST() for i in arr: - root = insert(root, i) - return root - - -def pre_order(root): - """print the tree by pre_order traversal""" - arr = [] - if root: - arr.append(root.data) - arr += pre_order(root.left) - arr += pre_order(root.right) - else: - return arr - return arr - + bst.insert(i) + return bst if __name__ == '__main__': #user input node_arr = raw_input('Please type in a list of node integer, seperated by space.\n') # insert nodes - root = build_bst(map(int, node_arr.split())) + bst = build_bst(map(int, node_arr.split())) # pre_order print - print 'Original bst list: \n %s\n' % str(pre_order(root)) + print 'Original bst list: \n %s\n' % str(bst.pre_order_print()) erase_keys = raw_input('Please type in key(s) you want to delete:\n') # check whether input is valid @@ -148,10 +181,9 @@ def pre_order(root): # check if key exists. for key in keys: - if has_key(root, key): - root = delete_node(root, key) - #print 'key %s is deleted from bst' % key + if bst.has_key(key): + bst.delete(key) else: print 'key %s not found.' % key - print 'New bst list:\n%s\n' % str(pre_order(root)) \ No newline at end of file + print 'New bst list:\n%s\n' % str(bst.pre_order_print()) \ No newline at end of file diff --git a/challenge_11/python/shaowen/unit_test.py b/challenge_11/python/shaowen/unit_test.py index 737d26f04..dc5313f98 100644 --- a/challenge_11/python/shaowen/unit_test.py +++ b/challenge_11/python/shaowen/unit_test.py @@ -3,51 +3,50 @@ import unittest -import bst -from bst import Node +from bst import BST, build_bst class bst_test(unittest.TestCase): # build proper bst list def test_bst_build_case1(self): arr = [5, 2, 12, 9, 21, 3, -4, 19, 25] - root = bst.build_bst(arr) - self.assertEqual(bst.pre_order(root), [5, 2, -4, 3, 12, 9, 21, 19, 25]) + bst = build_bst(arr) + self.assertEqual(bst.pre_order_print(), [5, 2, -4, 3, 12, 9, 21, 19, 25]) def test_bst_build_case2(self): arr = [235, 100, 50, 700, 800, 900, 25, 75, 105, 236] - root = bst.build_bst(arr) - self.assertEqual(bst.pre_order(root), [235,100,50,25,75,105,700,236,800,900]) + bst = build_bst(arr) + self.assertEqual(bst.pre_order_print(), [235,100,50,25,75,105,700,236,800,900]) # test for delete method def test_bst_delete_case1(self): # delete the leaf node - bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] - root = bst.build_bst(bst_list) - root = bst.delete_node(root,25) - self.assertEqual(bst.pre_order(root), [5, 2, -4, 3, 12, 9, 21, 19]) + arr = [5, 2, -4, 3, 12, 9, 21, 19, 25] + bst = build_bst(arr) + bst.delete(25) + self.assertEqual(bst.pre_order_print(), [5, 2, -4, 3, 12, 9, 21, 19]) def test_bst_delete_case2(self): # delete the roof node - bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] - root = bst.build_bst(bst_list) - root = bst.delete_node(root,5) - self.assertEqual(bst.pre_order(root), [9, 2, -4, 3, 12, 21, 19, 25]) + arr = [5, 2, -4, 3, 12, 9, 21, 19, 25] + bst = build_bst(arr) + bst.delete(5) + self.assertEqual(bst.pre_order_print(), [9, 2, -4, 3, 12, 21, 19, 25]) def test_bst_delete_case3(self): # delete the node in the middle of the tree bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] - root = bst.build_bst(bst_list) - root = bst.delete_node(root,2) - self.assertEqual(bst.pre_order(root), [5, 3, -4, 12, 9, 21, 19, 25]) + bst = build_bst(bst_list) + bst.delete(2) + self.assertEqual(bst.pre_order_print(), [5, 3, -4, 12, 9, 21, 19, 25]) def test_bst_delete_case4(self): # delete the node in the middle of the tree - bst_list = [5, 2, -4, 3, 12, 9, 21, 19, 25] - root = bst.build_bst(bst_list) - root = bst.delete_node(root,12) - self.assertEqual(bst.pre_order(root), [5, 2, -4, 3, 19, 9, 21, 25]) + arr = [5, 2, -4, 3, 12, 9, 21, 19, 25] + bst = build_bst(arr) + bst.delete(12) + self.assertEqual(bst.pre_order_print(), [5, 2, -4, 3, 19, 9, 21, 25]) From 48bfb46104952de7b2ac442fcfafc2c2a684c7a7 Mon Sep 17 00:00:00 2001 From: shaowenliu Date: Sat, 14 Jan 2017 08:56:41 +0800 Subject: [PATCH 9/9] [python2]challenge_12(Unreviewed) --- challenge_12/python/shaowen/READE.md | 14 ++++++++++ challenge_12/python/shaowen/compress.py | 37 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 challenge_12/python/shaowen/READE.md create mode 100644 challenge_12/python/shaowen/compress.py diff --git a/challenge_12/python/shaowen/READE.md b/challenge_12/python/shaowen/READE.md new file mode 100644 index 000000000..9d986b1b8 --- /dev/null +++ b/challenge_12/python/shaowen/READE.md @@ -0,0 +1,14 @@ +###Challenge 12 + +Language Version: Python 2.7.12 + + +### Solution + +Regex + +### How to run + +$ python compress.py + +(code will detect whether it's compressed or not, and output the opposite.) diff --git a/challenge_12/python/shaowen/compress.py b/challenge_12/python/shaowen/compress.py new file mode 100644 index 000000000..06b343db7 --- /dev/null +++ b/challenge_12/python/shaowen/compress.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +#@author: Shaowen Liu + +import re + +def replace_fun(match): + duplicated = match.group() + return '%s#%d' % (duplicated[0], len(duplicated)) + +def replace_fun2(match): + compressed = match.group() + return compressed[0] * int(compressed[2:]) + +def compress(astring): + """compress string""" + pattern = re.compile(r'(([a-zA-Z])\2{3,})') + + return pattern.sub(replace_fun, astring) + +def decompress(astring): + """decompress string""" + pattern = re.compile(r'(\w#\d+)') + + return pattern.sub(replace_fun2, astring) + +if __name__ == '__main__': + astring = raw_input('Input string:') + + if '#' in astring: + decompress_str = decompress(astring) + print 'Decopressed string:\n%s\n' % decompress_str + else: + compress_str = compress(astring) + print 'Compressed string: \n%s\n' % compress_str + + + \ No newline at end of file