diff --git a/.gitignore b/.gitignore index 4f4df79..42ab69d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ *.tar.gz *.rar *.DS_Store +*.exe # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/README.md b/README.md index 46004e7..7d077a8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,74 @@ -# 数据结构和算法之美 -# [https://time.geekbang.org/column/intro/126](https://time.geekbang.org/column/intro/126) +# 数据结构和算法必知必会的50个代码实现 -# Java rate limiting library/framework -# https://github.com/wangzheng0822/ratelimiter4j +## 数组 +* 实现一个支持动态扩容的数组 +* 实现一个大小固定的有序数组,支持动态增删改操作 +* 实现两个有序数组合并为一个有序数组 +## 链表 +* 实现单链表、循环链表、双向链表,支持增删操作 +* 实现单链表反转 +* 实现两个有序的链表合并为一个有序链表 +* 实现求链表的中间结点 + +## 栈 +* 用数组实现一个顺序栈 +* 用链表实现一个链式栈 +* 编程模拟实现一个浏览器的前进、后退功能 + +## 队列 +* 用数组实现一个顺序队列 +* 用链表实现一个链式队列 +* 实现一个循环队列 + +## 递归 +* 编程实现斐波那契数列求值f(n)=f(n-1)+f(n-2) +* 编程实现求阶乘n! +* 编程实现一组数据集合的全排列 + +## 排序 +* 实现归并排序、快速排序、插入排序、冒泡排序、选择排序 +* 编程实现O(n)时间复杂度内找到一组数据的第K大元素 + +## 二分查找 +* 实现一个有序数组的二分查找算法 +* 实现模糊二分查找算法(比如大于等于给定值的第一个元素) + +## 散列表 +* 实现一个基于链表法解决冲突问题的散列表 +* 实现一个LRU缓存淘汰算法 + +## 字符串 +* 实现一个字符集,只包含a~z这26个英文字母的Trie树 +* 实现朴素的字符串匹配算法 + +## 二叉树 +* 实现一个二叉查找树,并且支持插入、删除、查找操作 +* 实现查找二叉查找树中某个节点的后继、前驱节点 +* 实现二叉树前、中、后序以及按层遍历 + +## 堆 +* 实现一个小顶堆、大顶堆、优先级队列 +* 实现堆排序 +* 利用优先级队列合并K个有序数组 +* 求一组动态数据集合的最大Top K + +## 图 +* 实现有向图、无向图、有权图、无权图的邻接矩阵和邻接表表示方法 +* 实现图的深度优先搜索、广度优先搜索 +* 实现Dijkstra算法、A*算法 +* 实现拓扑排序的Kahn算法、DFS算法 + +## 回溯 +* 利用回溯算法求解八皇后问题 +* 利用回溯算法求解0-1背包问题 + +## 分治 +* 利用分治算法求一组数据的逆序对个数 + +## 动态规划 +* 0-1背包问题 +* 最小路径和 +* 编程实现莱文斯坦最短编辑距离 +* 编程实现查找两个字符串的最长公共子序列 +* 编程实现一个数据序列的最长递增子序列 diff --git a/csharp/05-array/Array.cs b/csharp/05-array/Array.cs index ecdc35f..3ceeaee 100644 --- a/csharp/05-array/Array.cs +++ b/csharp/05-array/Array.cs @@ -1,6 +1,6 @@ using System; -namespace _05_array +namespace algo05_array { public sealed class Array where T : IComparable { diff --git a/csharp/05-array/_05_array.csproj b/csharp/05-array/algo05_array.csproj similarity index 99% rename from csharp/05-array/_05_array.csproj rename to csharp/05-array/algo05_array.csproj index 68495a7..70e59c9 100644 --- a/csharp/05-array/_05_array.csproj +++ b/csharp/05-array/algo05_array.csproj @@ -2,7 +2,6 @@ netcoreapp2.2 - false diff --git a/csharp/06-linkedlist/LRUWithArray.cs b/csharp/06-linkedlist/LRUWithArray.cs index 69603ed..cc733a7 100644 --- a/csharp/06-linkedlist/LRUWithArray.cs +++ b/csharp/06-linkedlist/LRUWithArray.cs @@ -1,7 +1,6 @@ -using System.Text.RegularExpressions; -using _05_array; +using algo05_array; -namespace _06_linked_list +namespace algo06_linked_list { /// /// 使用数组实现LRU缓存淘汰算法 diff --git a/csharp/06-linkedlist/LRUWithLinkedList.cs b/csharp/06-linkedlist/LRUWithLinkedList.cs index a96d427..2812352 100644 --- a/csharp/06-linkedlist/LRUWithLinkedList.cs +++ b/csharp/06-linkedlist/LRUWithLinkedList.cs @@ -1,4 +1,4 @@ -namespace _06_linked_list +namespace algo06_linked_list { /// /// 使用单链表实现LRU缓存淘汰算法 diff --git a/csharp/06-linkedlist/SingleLinkedList.cs b/csharp/06-linkedlist/SingleLinkedList.cs index 6b7bd83..cb0537d 100644 --- a/csharp/06-linkedlist/SingleLinkedList.cs +++ b/csharp/06-linkedlist/SingleLinkedList.cs @@ -1,6 +1,6 @@ using System; -namespace _06_linked_list +namespace algo06_linked_list { /// /// 单链表的插入、删除、清空、查找 diff --git a/csharp/06-linkedlist/_06_linked_list.csproj b/csharp/06-linkedlist/algo06_linked_list.csproj similarity index 75% rename from csharp/06-linkedlist/_06_linked_list.csproj rename to csharp/06-linkedlist/algo06_linked_list.csproj index 66e10c4..0b68f2f 100644 --- a/csharp/06-linkedlist/_06_linked_list.csproj +++ b/csharp/06-linkedlist/algo06_linked_list.csproj @@ -7,7 +7,7 @@ - + diff --git a/csharp/07-linkedlist/_07_linkedlist/SingleLinkedListAlgo.cs b/csharp/07-linkedlist/_07_linkedlist/SingleLinkedListAlgo.cs index 061a9a1..f0d3e49 100644 --- a/csharp/07-linkedlist/_07_linkedlist/SingleLinkedListAlgo.cs +++ b/csharp/07-linkedlist/_07_linkedlist/SingleLinkedListAlgo.cs @@ -1,7 +1,7 @@ using System; -using _06_linked_list; +using algo06_linked_list; -namespace _07_linkedlist +namespace algo07_linkedlist { /// /// 单链表常用算法操作 diff --git a/csharp/07-linkedlist/_07_linkedlist/_07_linkedlist.csproj b/csharp/07-linkedlist/_07_linkedlist/algo07_linkedlist.csproj similarity index 68% rename from csharp/07-linkedlist/_07_linkedlist/_07_linkedlist.csproj rename to csharp/07-linkedlist/_07_linkedlist/algo07_linkedlist.csproj index 0080a55..0e988e2 100644 --- a/csharp/07-linkedlist/_07_linkedlist/_07_linkedlist.csproj +++ b/csharp/07-linkedlist/_07_linkedlist/algo07_linkedlist.csproj @@ -5,7 +5,7 @@ - + diff --git a/csharp/08-stack/algo08_stack/ArrayStack.cs b/csharp/08-stack/algo08_stack/ArrayStack.cs new file mode 100644 index 0000000..c8b1e9f --- /dev/null +++ b/csharp/08-stack/algo08_stack/ArrayStack.cs @@ -0,0 +1,41 @@ +using System; + +namespace algo08_stack +{ + public class ArrayStack + { + private readonly int _capacity; + + private readonly T[] _data; + + private int _top = -1; // 指向栈顶元素,当为-1时表示栈为空 + + public ArrayStack(int capacity) + { + _capacity = capacity; + + _data = new T[capacity]; + } + + public int Count => _top + 1; + + public void Push(T val) + { + if (Count == _capacity) throw new InvalidOperationException("Stack full."); + + _top++; + + _data[_top] = val; + } + + public T Pop() + { + if (_top == -1) throw new InvalidOperationException("Stack empty."); + + T val = _data[_top]; + _top--; + + return val; + } + } +} \ No newline at end of file diff --git a/csharp/08-stack/algo08_stack/LinkedStack.cs b/csharp/08-stack/algo08_stack/LinkedStack.cs new file mode 100644 index 0000000..f001770 --- /dev/null +++ b/csharp/08-stack/algo08_stack/LinkedStack.cs @@ -0,0 +1,51 @@ +using System; + +namespace algo08_stack +{ + public class LinkedStack + { + private StackListNode _top; + + public int Count { get; private set; } + + public void Push(T val) + { + var newNode = new StackListNode(val); + newNode.Next = _top; + _top = newNode; + + Count++; + } + + public T Pop() + { + if (_top == null) throw new InvalidOperationException("Stack empty"); + + T val = _top.Value; + _top = _top.Next; + + Count--; + + return val; + } + + public void Clear() + { + while (Count > 0) + { + Pop(); + } + } + } + + public class StackListNode + { + public StackListNode(T nodeValue) + { + Value = nodeValue; + } + + public T Value { get; set; } + public StackListNode Next { get; set; } + } +} \ No newline at end of file diff --git a/csharp/08-stack/algo08_stack/LinkedStackBrowser.cs b/csharp/08-stack/algo08_stack/LinkedStackBrowser.cs new file mode 100644 index 0000000..ad06ad0 --- /dev/null +++ b/csharp/08-stack/algo08_stack/LinkedStackBrowser.cs @@ -0,0 +1,39 @@ +namespace algo08_stack +{ + /// + /// 利用链栈实现浏览器怎么进后退 + /// + public class LinkedStackBrowser + { + private readonly LinkedStack _backStack = new LinkedStack(); + private readonly LinkedStack _forwardStack = new LinkedStack(); + + public void Open(string url) + { + _backStack.Push(url); + + _forwardStack.Clear(); + } + + public string Backward() + { + if (_backStack.Count == 0) return string.Empty; + + string url = _backStack.Pop(); + + _forwardStack.Push(url); + + return url; + } + + public string Forward() + { + if (_forwardStack.Count == 0) return string.Empty; + + string url = _forwardStack.Pop(); + _backStack.Push(url); + + return url; + } + } +} \ No newline at end of file diff --git a/csharp/08-stack/algo08_stack/algo08_stack.csproj b/csharp/08-stack/algo08_stack/algo08_stack.csproj new file mode 100644 index 0000000..ec0b0b9 --- /dev/null +++ b/csharp/08-stack/algo08_stack/algo08_stack.csproj @@ -0,0 +1,7 @@ + + + + netcoreapp2.2 + + + diff --git a/csharp/Tests/_05_array_tests/Array.Tests.cs b/csharp/Tests/_05_array_tests/Array.Tests.cs index f5cae7c..5e4f88f 100644 --- a/csharp/Tests/_05_array_tests/Array.Tests.cs +++ b/csharp/Tests/_05_array_tests/Array.Tests.cs @@ -1,7 +1,7 @@ using System; +using algo05_array; using Xunit; using Xunit.Abstractions; -using _05_array; namespace _05_array_tests { diff --git a/csharp/Tests/_05_array_tests/_05_array_tests.csproj b/csharp/Tests/_05_array_tests/algo05_array_tests.csproj similarity index 87% rename from csharp/Tests/_05_array_tests/_05_array_tests.csproj rename to csharp/Tests/_05_array_tests/algo05_array_tests.csproj index d0fa21a..2e90daa 100644 --- a/csharp/Tests/_05_array_tests/_05_array_tests.csproj +++ b/csharp/Tests/_05_array_tests/algo05_array_tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/csharp/Tests/_06_linkedlist_tests/BaseLinkedListTests.cs b/csharp/Tests/_06_linkedlist_tests/BaseLinkedListTests.cs index e36298c..2a6a72d 100644 --- a/csharp/Tests/_06_linkedlist_tests/BaseLinkedListTests.cs +++ b/csharp/Tests/_06_linkedlist_tests/BaseLinkedListTests.cs @@ -1,7 +1,7 @@ using System; -using _06_linked_list; +using algo06_linked_list; -namespace _06_linkedlist_tests +namespace algo06_linkedlist_tests { public class BaseLinkedListTests { diff --git a/csharp/Tests/_06_linkedlist_tests/LRUWithArray.Tests.cs b/csharp/Tests/_06_linkedlist_tests/LRUWithArray.Tests.cs index 449e8d7..88fcec5 100644 --- a/csharp/Tests/_06_linkedlist_tests/LRUWithArray.Tests.cs +++ b/csharp/Tests/_06_linkedlist_tests/LRUWithArray.Tests.cs @@ -1,9 +1,9 @@ +using algo05_array; +using algo06_linked_list; using Xunit; using Xunit.Abstractions; -using _05_array; -using _06_linked_list; -namespace _06_linkedlist_tests +namespace algo06_linkedlist_tests { public class LRUWithArrayTests { diff --git a/csharp/Tests/_06_linkedlist_tests/LRUWithLinkedList.Tests.cs b/csharp/Tests/_06_linkedlist_tests/LRUWithLinkedList.Tests.cs index 11a343d..3136d92 100644 --- a/csharp/Tests/_06_linkedlist_tests/LRUWithLinkedList.Tests.cs +++ b/csharp/Tests/_06_linkedlist_tests/LRUWithLinkedList.Tests.cs @@ -1,8 +1,8 @@ using Xunit; using Xunit.Abstractions; -using _06_linked_list; +using algo06_linked_list; -namespace _06_linkedlist_tests +namespace algo06_linkedlist_tests { public class LRUWithLinkedListTests : BaseLinkedListTests { diff --git a/csharp/Tests/_06_linkedlist_tests/SingleLinkedList.Tests.cs b/csharp/Tests/_06_linkedlist_tests/SingleLinkedList.Tests.cs index 525665e..8f577b7 100644 --- a/csharp/Tests/_06_linkedlist_tests/SingleLinkedList.Tests.cs +++ b/csharp/Tests/_06_linkedlist_tests/SingleLinkedList.Tests.cs @@ -1,9 +1,9 @@ using System; using Xunit; using Xunit.Abstractions; -using _06_linked_list; +using algo06_linked_list; -namespace _06_linkedlist_tests +namespace algo06_linkedlist_tests { public class SingleLinkedListTests : BaseLinkedListTests { diff --git a/csharp/Tests/_06_linkedlist_tests/_06_linkedlist_tests.csproj b/csharp/Tests/_06_linkedlist_tests/algo06_linkedlist_tests.csproj similarity index 68% rename from csharp/Tests/_06_linkedlist_tests/_06_linkedlist_tests.csproj rename to csharp/Tests/_06_linkedlist_tests/algo06_linkedlist_tests.csproj index dc95495..fad3825 100644 --- a/csharp/Tests/_06_linkedlist_tests/_06_linkedlist_tests.csproj +++ b/csharp/Tests/_06_linkedlist_tests/algo06_linkedlist_tests.csproj @@ -2,7 +2,6 @@ netcoreapp2.2 - _06_linkedlist_tests false @@ -14,8 +13,8 @@ - - + + diff --git a/csharp/Tests/_07_linkedlist_tests/SingleLinkedListAlgo.Tests.cs b/csharp/Tests/_07_linkedlist_tests/SingleLinkedListAlgo.Tests.cs index aa5f093..9527f6a 100644 --- a/csharp/Tests/_07_linkedlist_tests/SingleLinkedListAlgo.Tests.cs +++ b/csharp/Tests/_07_linkedlist_tests/SingleLinkedListAlgo.Tests.cs @@ -1,10 +1,10 @@ using System; using Xunit; -using _06_linkedlist_tests; -using _06_linked_list; -using _07_linkedlist; +using algo06_linkedlist_tests; +using algo06_linked_list; +using algo07_linkedlist; -namespace _07_linkedlist_tests +namespace algo07_linkedlist_tests { public class SingleLinkedListAlgoTests : BaseLinkedListTests { diff --git a/csharp/Tests/_07_linkedlist_tests/_07_linkedlist_tests.csproj b/csharp/Tests/_07_linkedlist_tests/algo07_linkedlist_tests.csproj similarity index 72% rename from csharp/Tests/_07_linkedlist_tests/_07_linkedlist_tests.csproj rename to csharp/Tests/_07_linkedlist_tests/algo07_linkedlist_tests.csproj index 53f9120..2e55887 100644 --- a/csharp/Tests/_07_linkedlist_tests/_07_linkedlist_tests.csproj +++ b/csharp/Tests/_07_linkedlist_tests/algo07_linkedlist_tests.csproj @@ -13,9 +13,9 @@ - - - + + + diff --git a/csharp/Tests/algo08_stack_tests/ArrayStack.Tests.cs b/csharp/Tests/algo08_stack_tests/ArrayStack.Tests.cs new file mode 100644 index 0000000..ec28a54 --- /dev/null +++ b/csharp/Tests/algo08_stack_tests/ArrayStack.Tests.cs @@ -0,0 +1,81 @@ +using System; +using algo08_stack; +using Xunit; +using Xunit.Abstractions; + +namespace algo08_stack_tests +{ + public class ArrayStackTests + { + private readonly ITestOutputHelper _output; + + public ArrayStackTests(ITestOutputHelper output) + { + _output = output; + } + + private void PrintStackArray(ArrayStack list) + { + if (list.Count == 0) return; + + while (list.Count > 0) + { + T item = list.Pop(); + _output.WriteLine(item.ToString()); + } + } + + [Fact] + public void Push_3_Elements_Then_Length_Equal_3() + { + var stack = new ArrayStack(5); + stack.Push(2); + stack.Push(4); + stack.Push(6); + + Assert.Equal(3, stack.Count); + + PrintStackArray(stack); + } + + [Fact] + public void Push_Throw_InvalidOperationException_When_Stack_Full() + { + var stack = new ArrayStack(5); + stack.Push(2); + stack.Push(4); + stack.Push(6); + stack.Push(8); + stack.Push(10); + + Exception ex = Assert.Throws(() => stack.Push(11)); + Assert.IsType(ex); + + PrintStackArray(stack); + } + + [Fact] + public void Pop_Throw_InvalidOperationException_When_Stack_Empty() + { + var stack = new ArrayStack(5); + + Exception ex = Assert.Throws(() => stack.Pop()); + Assert.IsType(ex); + + PrintStackArray(stack); + } + + [Fact] + public void Pop_Valid_When_Stack_Not_Empty() + { + var stack = new ArrayStack(5); + stack.Push(2); + stack.Push(4); + + int val = stack.Pop(); + Assert.Equal(4, val); + + PrintStackArray(stack); + } + } +} \ No newline at end of file diff --git a/csharp/Tests/algo08_stack_tests/LinkedStack.Tests.cs b/csharp/Tests/algo08_stack_tests/LinkedStack.Tests.cs new file mode 100644 index 0000000..8191692 --- /dev/null +++ b/csharp/Tests/algo08_stack_tests/LinkedStack.Tests.cs @@ -0,0 +1,65 @@ +using System; +using algo08_stack; +using Xunit; +using Xunit.Abstractions; + +namespace algo08_stack_tests +{ + public class LinkedStackTests + { + private readonly ITestOutputHelper _output; + + public LinkedStackTests(ITestOutputHelper output) + { + _output = output; + } + + private void PrintStackLinkedList(LinkedStack list) + { + if (list.Count == 0) return; + + while (list.Count > 0) + { + var val = list.Pop(); + _output.WriteLine(val.ToString()); + } + } + + [Fact] + public void Push_3_Elements_Then_Length_Equal_3() + { + var stack = new LinkedStack(); + stack.Push(2); + stack.Push(4); + stack.Push(6); + + Assert.Equal(3, stack.Count); + + PrintStackLinkedList(stack); + } + + [Fact] + public void Pop_Throw_InvalidOperationException_When_Stack_Empty() + { + var stack = new LinkedStack(); + + Exception ex = Assert.Throws(() => stack.Pop()); + Assert.IsType(ex); + + PrintStackLinkedList(stack); + } + + [Fact] + public void Pop_Valid_When_Stack_Not_Empty() + { + var stack = new LinkedStack(); + stack.Push(2); + stack.Push(4); + + var nodeVal = stack.Pop(); + Assert.Equal(4, nodeVal); + + PrintStackLinkedList(stack); + } + } +} \ No newline at end of file diff --git a/csharp/Tests/algo08_stack_tests/LinkedStackBrowser.Tests.cs b/csharp/Tests/algo08_stack_tests/LinkedStackBrowser.Tests.cs new file mode 100644 index 0000000..5d0a113 --- /dev/null +++ b/csharp/Tests/algo08_stack_tests/LinkedStackBrowser.Tests.cs @@ -0,0 +1,107 @@ +using algo08_stack; +using Xunit; +using Xunit.Abstractions; + +namespace algo08_stack_tests +{ + public class LinkedStackBrowserTests + { + private readonly ITestOutputHelper _output; + + public LinkedStackBrowserTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void Browser_Open_4_Links_Back_2_Return_Right_Link() + { + var browser = new LinkedStackBrowser(); + browser.Open("www.google.com"); + browser.Open("www.baidu.com"); + browser.Open("www.qq.com"); + browser.Open("www.dadu.com"); + + string url = browser.Backward(); + url = browser.Backward(); + + Assert.Equal("www.qq.com", url); + } + + [Fact] + public void Browser_Open_4_Links_Back_4_Return_Empty() + { + var browser = new LinkedStackBrowser(); + browser.Open("www.google.com"); + browser.Open("www.baidu.com"); + browser.Open("www.qq.com"); + browser.Open("www.dadu.com"); + + browser.Backward(); + browser.Backward(); + browser.Backward(); + browser.Backward(); + string url = browser.Backward(); + + Assert.Equal(string.Empty, url); + } + + [Fact] + public void Browser_Forward_Before_End() + { + var browser = new LinkedStackBrowser(); + browser.Open("www.google.com"); + browser.Open("www.baidu.com"); + browser.Open("www.qq.com"); + browser.Open("www.dadu.com"); + + browser.Backward(); + browser.Backward(); + browser.Backward(); + + browser.Forward(); + string url = browser.Forward(); + + Assert.Equal("www.qq.com", url); + } + + [Fact] + public void Browser_Forward_Until_End() + { + var browser = new LinkedStackBrowser(); + browser.Open("www.google.com"); + browser.Open("www.baidu.com"); + browser.Open("www.qq.com"); + browser.Open("www.dadu.com"); + + browser.Backward(); + browser.Backward(); + browser.Backward(); + + browser.Forward(); + browser.Forward(); + browser.Forward(); + string url = browser.Forward(); + + Assert.Equal(string.Empty, url); + } + + [Fact] + public void Browser_Backward_And_Open_New_Then_Cannot_Forward() + { + var browser = new LinkedStackBrowser(); + browser.Open("www.google.com"); + browser.Open("www.baidu.com"); + browser.Open("www.qq.com"); + + browser.Backward(); + browser.Backward(); + + browser.Open("www.dadu.com"); + + string url = browser.Forward(); + + Assert.Equal(string.Empty, url); + } + } +} \ No newline at end of file diff --git a/csharp/Tests/algo08_stack_tests/algo08_stack_tests.csproj b/csharp/Tests/algo08_stack_tests/algo08_stack_tests.csproj new file mode 100644 index 0000000..0c4d1a4 --- /dev/null +++ b/csharp/Tests/algo08_stack_tests/algo08_stack_tests.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.2 + + false + + + + + + + + + + + + + diff --git a/csharp/csharp.sln b/csharp/csharp.sln index 402e969..1f4b949 100644 --- a/csharp/csharp.sln +++ b/csharp/csharp.sln @@ -3,19 +3,23 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_05_array", "05-array\_05_array.csproj", "{B88033F6-FF08-434A-AED7-91F5CDB73402}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo05_array", "05-array\algo05_array.csproj", "{B88033F6-FF08-434A-AED7-91F5CDB73402}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_06_linked_list", "06-linkedlist\_06_linked_list.csproj", "{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo06_linked_list", "06-linkedlist\algo06_linked_list.csproj", "{29CABAFB-2581-42D1-ABD9-F0D9E0BB8DC2}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B0248987-EEDF-4D93-8E12-C00B1EB5B6CB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_05_array_tests", "Tests\_05_array_tests\_05_array_tests.csproj", "{14982212-49E4-4409-8BFD-2D8A2945BD83}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo05_array_tests", "Tests\_05_array_tests\algo05_array_tests.csproj", "{14982212-49E4-4409-8BFD-2D8A2945BD83}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_06_linkedlist_tests", "Tests\_06_linkedlist_tests\_06_linkedlist_tests.csproj", "{1B93D9C6-D6C1-4619-BFB9-D84C29099223}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo06_linkedlist_tests", "Tests\_06_linkedlist_tests\algo06_linkedlist_tests.csproj", "{1B93D9C6-D6C1-4619-BFB9-D84C29099223}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_07_linkedlist", "07-linkedlist\_07_linkedlist\_07_linkedlist.csproj", "{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo07_linkedlist", "07-linkedlist\_07_linkedlist\algo07_linkedlist.csproj", "{5A4CCBB9-F683-4436-AAEE-4B3ABA76936B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "_07_linkedlist_tests", "Tests\_07_linkedlist_tests\_07_linkedlist_tests.csproj", "{66C3BC00-C135-4279-A666-A330A86F20D5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo07_linkedlist_tests", "Tests\_07_linkedlist_tests\algo07_linkedlist_tests.csproj", "{66C3BC00-C135-4279-A666-A330A86F20D5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo08_stack", "08-stack\algo08_stack\algo08_stack.csproj", "{E080D481-C98E-43F3-B1D1-51DCF4CF7146}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algo08_stack_tests", "Tests\algo08_stack_tests\algo08_stack_tests.csproj", "{6A249475-54EA-4039-9B0C-DC0E0A884C07}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -102,10 +106,35 @@ Global {66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x64.Build.0 = Release|Any CPU {66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x86.ActiveCfg = Release|Any CPU {66C3BC00-C135-4279-A666-A330A86F20D5}.Release|x86.Build.0 = Release|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x64.ActiveCfg = Debug|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x64.Build.0 = Debug|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x86.ActiveCfg = Debug|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Debug|x86.Build.0 = Debug|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|Any CPU.Build.0 = Release|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x64.ActiveCfg = Release|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x64.Build.0 = Release|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x86.ActiveCfg = Release|Any CPU + {E080D481-C98E-43F3-B1D1-51DCF4CF7146}.Release|x86.Build.0 = Release|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x64.ActiveCfg = Debug|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x64.Build.0 = Debug|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x86.ActiveCfg = Debug|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Debug|x86.Build.0 = Debug|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|Any CPU.Build.0 = Release|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x64.ActiveCfg = Release|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x64.Build.0 = Release|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x86.ActiveCfg = Release|Any CPU + {6A249475-54EA-4039-9B0C-DC0E0A884C07}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {14982212-49E4-4409-8BFD-2D8A2945BD83} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB} {1B93D9C6-D6C1-4619-BFB9-D84C29099223} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB} {66C3BC00-C135-4279-A666-A330A86F20D5} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB} + {6A249475-54EA-4039-9B0C-DC0E0A884C07} = {B0248987-EEDF-4D93-8E12-C00B1EB5B6CB} EndGlobalSection EndGlobal diff --git a/go/06_linkedlist/palindrome-linked-list.go b/go/06_linkedlist/palindrome-linked-list.go new file mode 100644 index 0000000..f9f2e4a --- /dev/null +++ b/go/06_linkedlist/palindrome-linked-list.go @@ -0,0 +1,41 @@ +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +func isPalindrome(head *ListNode) bool { + var slow *ListNode = head + var fast *ListNode = head + var prev *ListNode = nil + var temp *ListNode = nil + + if (head == nil || head.Next == nil) { + return true + } + + for (fast != nil && fast.Next !=nil){ + fast = fast.Next.Next + temp = slow.Next + slow.Next = prev + prev = slow + slow = temp + } // 快的先跑完,同时反转了一半链表,剪短 + + if fast != nil { + slow = slow.Next // 处理余数,跨过中位数 + // prev 增加中 2->1->nil + } + + var l1 *ListNode = prev + var l2 *ListNode = slow + + for (l1 != nil && l2 !=nil && l1.Val == l2.Val){ + l1 = l1.Next + l2 = l2.Next + } + + return (l1 == nil && l2 == nil) + + } diff --git a/go/34_kmp/kmp.go b/go/34_kmp/kmp.go new file mode 100644 index 0000000..75941f1 --- /dev/null +++ b/go/34_kmp/kmp.go @@ -0,0 +1,73 @@ +package main + +import ( + "fmt" +) + +func getNexts(pattern string) []int { + m := len(pattern) + nexts := make([]int, m) + for index := range nexts { + nexts[index] = -1 + } + + for i := 1; i < m - 1; i++ { + j := nexts[i - 1] + + for pattern[j + 1] != pattern[i] && j >= 0 { + j = nexts[j] + } + + if pattern[j + 1] == pattern[i] { + j += 1 + } + + nexts[i] = j + } + + return nexts +} + +func findByKMP(s string, pattern string) int { + n := len(s) + m := len(pattern) + if n < m { + return -1 + } + + nexts := getNexts(pattern) + + j := 0 + for i := 0; i < n; i++ { + for j > 0 && s[i] != pattern[j] { + j = nexts[j - 1] + 1 + } + + if s[i] == pattern[j] { + if j == m - 1 { + return i - m + 1 + } + j += 1 + } + } + + return -1 +} + +func main(){ + s := "abc abcdab abcdabcdabde" + pattern := "bcdabd" + fmt.Println(findByKMP(s, pattern)) //16 + + s = "aabbbbaaabbababbabbbabaaabb" + pattern = "abab" + fmt.Println(findByKMP(s, pattern)) //11 + + s = "aabbbbaaabbababbabbbabaaabb" + pattern = "ababacd" + fmt.Println(findByKMP(s, pattern)) //-1 + + s = "hello" + pattern = "ll" + fmt.Println(findByKMP(s, pattern)) //2 +} \ No newline at end of file diff --git a/go/45_bitmap/bitmap.go b/go/45_bitmap/bitmap.go new file mode 100644 index 0000000..7f03685 --- /dev/null +++ b/go/45_bitmap/bitmap.go @@ -0,0 +1,29 @@ +package bitmap + +// BitMap implement bitmap +type BitMap []byte + +// New create BitMap +func New(length uint) BitMap { + return make([]byte, length/8+1) +} + +// Set set value in bitmap +func (b BitMap) Set(value uint) { + byteIndex := value / 8 + if byteIndex >= uint(len(b)) { + return + } + bitIndex := value % 8 + []byte(b)[byteIndex] |= 1 << bitIndex +} + +// Get check whether value exist or not +func (b BitMap) Get(value uint) bool { + byteIndex := value / 8 + if byteIndex >= uint(len(b)) { + return false + } + bitIndex := value % 8 + return []byte(b)[byteIndex]&(1< { * @param object */ public void removeAndCache(T object) { - value[--count] = null; + T key = value[--count]; + holder.remove(key); cache(object, count); } diff --git a/javascript/05_array/Array.md b/javascript/05_array/Array.md index 5af2394..d2784d1 100644 --- a/javascript/05_array/Array.md +++ b/javascript/05_array/Array.md @@ -151,7 +151,7 @@ function isEven(num){ } var num = [1,2,3,4,5,6,7,8]; var someEven = num.some(isEven); -if(even){ +if(someEven){ console.log("有些数字是偶数"); }else{ console.log("没有数字是偶数"); @@ -208,14 +208,24 @@ console.log(pass); #### 二维数组 JavaScript 可以通过在数组里在嵌套一个数组来形成二维数组。 ``` -var grades = [[88,86,82],[91,82,83],[77,72,79]]; +var grades = [ + [88,86,82], + [91,82,83], + [77,72,79], + [86,80,82] +]; console.log(grades[1][2]); // 83 ``` #### 处理二维数组 对于二维数组的处理可以分为两种,一种按列访问,一种是按行访问。 -按列访问,外层循环对应行,内层循环对应列。例如,上述的数组,每一行对应一个学生的成绩记录,可以通过相加所有成绩,然后除以科目数来得到该生的平均成绩。 +按列访问,外层循环对应行,内层循环对应列。例如,上述的数组,每一行对应一个学生三门科目的成绩记录,可以通过相加所有成绩,然后除以科目数来得到该生的平均成绩。 ``` -var grades = [[88,86,82],[91,82,83],[77,72,79]]; +var grades = [ + [88,86,82], + [91,82,83], + [77,72,79], + [86,80,82] +]; var total = 0; var average = 0.0; for(var row = 0;row student 1 average: 85.33 student 2 average: 85.33 student 3 average: 76.00 +student 4 average: 82.67 -对于按行访问,则外层循环对应列,内城循环对应行,例如还是上述数组,现在的数组表示一个学生各科的分数,我们来求其平均成绩 +对于按行访问,则外层循环对应列,内层循环对应行,例如还是上述数组,现在的数组表示一个学生三场考试四门科目的各科分数,我们来求每场考试的平均成绩 ``` -var grades = [[88,86,82],[91,82,83],[77,72,79]]; +var grades = [ + [88,86,82], + [91,82,83], + [77,72,79], + [86,80,82] +]; var total = 0; var average = 0.0; -for(var col = 0;col exam 1 average: 85.33 +> exam 1 average: 85.50 exam 2 average: 80.00 -exam 3 average: 81.33 +exam 3 average: 81.50 其实只要调整 for 循环的顺序就可以控制是按行还是按列来输出,此外,JavaScript 还可以处理一些参差不齐的数组,比如一个二维数组中的数组,有的是两个元素,有的是四个元素,并不是都相同,在这种情况下,JavaScript 依然可以处理运行而不报错,这是因为不管多或少,都可以通过 length 属性来计算。 #### 对象数组 diff --git a/javascript/35_trie/trie.js b/javascript/35_trie/trie.js new file mode 100644 index 0000000..8f3f409 --- /dev/null +++ b/javascript/35_trie/trie.js @@ -0,0 +1,56 @@ + + +class TrieNode { + constructor(data){ + this.data = data; + this.children = new Array(26); + this.isEndingChar = false + } +} + +class TrieTree { + + constructor(data){ + this.root = new TrieNode('/') + } + + insert (text) { + let node = this.root; + for (let char of text) { + let index = char.charCodeAt() - 'a'.charCodeAt(); + if(!node.children[index]) { + node.children[index] = new TrieNode(char); + } + node = node.children[index]; + } + + node.isEndingChar = true; + } + + find (text) { + let node = this.root; + + for(let char of text) { + let index = char.charCodeAt() - 'a'.charCodeAt(); + if(node.children[index]) { + node = node.children[index]; + } else { + return false; + } + } + + return node.isEndingChar; + } +} + +var tree = new TrieTree(); +var strs = ["how", "hi", "her", "hello", "so", "see"]; +for(let str of strs) { + tree.insert(str); +} + +for(let str of strs) { + console.log(tree.find(str)); +} + +console.log(tree.find('world')); \ No newline at end of file diff --git a/javascript/36_ac_automata/ac_automata.js b/javascript/36_ac_automata/ac_automata.js new file mode 100644 index 0000000..06e4071 --- /dev/null +++ b/javascript/36_ac_automata/ac_automata.js @@ -0,0 +1,103 @@ + +MAX_LEN = 128; + +class ACNode { + constructor(data){ + this.data = data; + this.children = new Array(MAX_LEN); + this.isEndingChar = false; + this.length = 0; + this.fail = null; + } +} + +class ACTree { + + constructor(data){ + this.root = new ACNode('/') + } + + insert (text) { + let node = this.root; + for (let char of text) { + let index = char.charCodeAt() + 1; + if(!node.children[index]) { + node.children[index] = new ACNode(char); + } + node = node.children[index]; + } + + node.isEndingChar = true; + node.length = text.length; + } + + buildFailurePointer() { + let root = this.root; + let queue = []; + queue.push(root); + + while (queue.length > 0) { + let p = queue.shift(); + + for (let i = 0; i < MAX_LEN; i++) { + let pc = p.children[i]; + if (!pc) { + continue; + } + + if(p == root) { + pc.fail = root; + } else { + let q = p.fail; + while (q) { + let qc = q.children[pc.data.charCodeAt() + 1]; + if(qc) { + pc.fail = qc; + break; + } + q = q.fail; + } + if(!q) { + pc.fail = root; + } + } + queue.push(pc); + } + } + } + + match (text) { + let root = this.root; + let n = text.length; + let p = root; + + for(let i = 0; i < n; i++) { + let idx = text[i].charCodeAt() + 1; + while(!p.children[idx] && p != root){ + p = p.fail; + } + + p = p.children[idx]; + if(!p) { + p = root; + } + + let tmp = p; + while ( tmp != root) { + if (tmp.isEndingChar == true) { + console.log(`Start from ${i - p.length + 1}, length: ${p.length}`); + } + tmp = tmp.fail; + } + } + } +} + +let automata = new ACTree(); +let patterns = ["at", "art", "oars", "soar"]; +for (let pattern of patterns) { + automata.insert(pattern); +} + +automata.buildFailurePointer() +automata.match("soarsoars"); \ No newline at end of file diff --git a/php/39_backtracking/queens.php b/php/39_backtracking/queens.php new file mode 100644 index 0000000..de99eef --- /dev/null +++ b/php/39_backtracking/queens.php @@ -0,0 +1,74 @@ +printQueens(); + return; + } + + //每一行有8中放法 + for($column = 0; $column < 8; $column++) { + if ($this->isOk($row, $column)) { + $this->result[$row] = $column; + $this->cal8queens($row + 1); + } + } + } + + //row行的column列是否合适 + function isOk($row, $column) + { + $leftup = $column - 1; + $rightdown = $column + 1; + + for ($i = $row - 1; $i >= 0; $i--) { + //判断上一行的 column 列是否有值 + if ($this->result[$i] == $column) { + return false; + } + + //左上角是否有值 + if ($leftup >= 0 && $this->result[$i] == $leftup) { + return false; + } + + //右下角是否有值 + if ($rightdown < 8 && $this->result[$i] == $rightdown) { + return false; + } + + $leftup--; + $rightdown++; + + } + + return true; + } + + //打印 + function printQueens() + { + for ($row = 0; $row < 8; $row++) { + for ($column = 0; $column < 8; $column++) { + if ($this->result[$row] == $column) { + echo 'Q'; + } else { + echo '*'; + } + } + echo '
'; + } + } +} + +$queen = new Queen(); +$queen->cal8queens(0); diff --git a/scala/src/main/scala/ch39_back_tracking/BagWeight.scala b/scala/src/main/scala/ch39_back_tracking/BagWeight.scala new file mode 100644 index 0000000..bfc5c21 --- /dev/null +++ b/scala/src/main/scala/ch39_back_tracking/BagWeight.scala @@ -0,0 +1,25 @@ +package ch39_back_tracking + +class BagWeight(maxBagItemCount: Int, maxBagWeight: Int) { + + def calculateMaxWeight(items: Array[Int]): Int = { + var maxWeight = 0 + + def _calcMaxWeight(itemIndex: Int, currentWeight: Int): Unit = { + if (currentWeight == maxBagWeight || itemIndex == items.length) { + if (currentWeight > maxWeight) { + maxWeight = currentWeight + } + } else { + //check next item + _calcMaxWeight(itemIndex + 1, currentWeight) + if (currentWeight + items(itemIndex) <= maxBagWeight) { + _calcMaxWeight(itemIndex + 1, currentWeight + items(itemIndex)) + } + } + } + + _calcMaxWeight(0, 0) + maxWeight + } +} diff --git a/scala/src/main/scala/ch39_back_tracking/EightQueens.scala b/scala/src/main/scala/ch39_back_tracking/EightQueens.scala new file mode 100644 index 0000000..fbb6d8a --- /dev/null +++ b/scala/src/main/scala/ch39_back_tracking/EightQueens.scala @@ -0,0 +1,78 @@ +package ch39_back_tracking + +import scala.util.control.Breaks._ + +class EightQueens { + + //use array index to identify the row,the value of the row to identify the column + val result = new Array[Int](8) + var count = 0 + + def calc8Queues(row: Int): Unit = { + if (row == 8) { + //everything is done + print8Queens() + return + } + + for (column <- Range(0, 8)) { + if (isOkOnColumn(row, column)) { + result(row) = column //place the column value into the array + calc8Queues(row + 1) //calculate next row + } + } + + } + + def isOkOnColumn(row: Int, column: Int): Boolean = { + var ok = true + var leftUp = column - 1 + var rightUp = column + 1 + + breakable { + //will compare all the rows above current row + for (i <- row - 1 to 0 by -1) { + //check current column + if (result(i) == column) { + ok = false + break + } + //check left up + if (leftUp >= 0) { + if (result(i) == leftUp) { + ok = false + break + } + } + //check right up + if (rightUp < 8) { + if (result(i) == rightUp) { + ok = false + break + } + } + //move leftUp and rightUp + leftUp -= 1 + rightUp += 1 + } + } + + ok + } + + def print8Queens(): Unit = { + count +=1 + for (row <- Range(0, 8)) { + for (column <- Range(0, 8)) { + if (result(row) == column) { + print("Q ") + } else { + print("* ") + } + } + //new line for next row + println("") + } + println(count+"==============") + } +} diff --git a/scala/src/main/scala/ch39_back_tracking/NQueens.scala b/scala/src/main/scala/ch39_back_tracking/NQueens.scala new file mode 100644 index 0000000..b600d22 --- /dev/null +++ b/scala/src/main/scala/ch39_back_tracking/NQueens.scala @@ -0,0 +1,77 @@ +package ch39_back_tracking + +import scala.util.control.Breaks.{break, breakable} + +class NQueens(numberOfQueens:Int) { + //use array index to identify the row,the value of the row to identify the column + val result = new Array[Int](numberOfQueens) + var count = 0 + + def calcNQueues(row: Int): Unit = { + if (row == numberOfQueens) { + //everything is done + printNQueens() + return + } + + for (column <- Range(0, numberOfQueens)) { + if (isOkOnColumn(row, column)) { + result(row) = column //place the column value into the array + calcNQueues(row + 1) //calculate next row + } + } + + } + + def isOkOnColumn(row: Int, column: Int): Boolean = { + var ok = true + var leftUp = column - 1 + var rightUp = column + 1 + + breakable { + //will compare all the rows above current row + for (i <- row - 1 to 0 by -1) { + //check current column + if (result(i) == column) { + ok = false + break + } + //check left up + if (leftUp >= 0) { + if (result(i) == leftUp) { + ok = false + break + } + } + //check right up + if (rightUp < numberOfQueens) { + if (result(i) == rightUp) { + ok = false + break + } + } + //move leftUp and rightUp + leftUp -= 1 + rightUp += 1 + } + } + + ok + } + + def printNQueens(): Unit = { + count +=1 + for (row <- Range(0, numberOfQueens)) { + for (column <- Range(0, numberOfQueens)) { + if (result(row) == column) { + print("Q ") + } else { + print("* ") + } + } + //new line for next row + println("") + } + println(count+"==============") + } +} diff --git a/scala/src/main/scala/ch39_back_tracking/Sudoku.scala b/scala/src/main/scala/ch39_back_tracking/Sudoku.scala new file mode 100644 index 0000000..64b7d74 --- /dev/null +++ b/scala/src/main/scala/ch39_back_tracking/Sudoku.scala @@ -0,0 +1,113 @@ +package ch39_back_tracking + +import scala.util.control.Breaks._ + +class Sudoku { + + def resolve(grid: Array[Array[Int]]): Unit = { + printGrid(grid) + println("") + if (resolve(grid, 0, 0)) { + printGrid(grid) + } else { + println("no result") + printGrid(grid) + } + } + + private[this] def resolve(grid: Array[Array[Int]], row: Int, column: Int): Boolean = { + if (row == 8 && column == 9) { + //find the result + return true + } + + if (column == 9) { + //move to next line + return resolve(grid, row + 1, 0) + } + + if (grid(row)(column) != 0) { + //given number, resolve next one + return resolve(grid, row, column + 1) + } + + //start the real resolve + for (num <- 1 to 9) { + if (isOk(grid, row, column, num)) { + grid(row)(column) = num + if (resolve(grid, row, column + 1)) { + return true + } + } + } + + //do not find anything, reset given row and column + grid(row)(column) = 0 + false + } + + def isOk(grid: Array[Array[Int]], row: Int, column: Int, num: Int): Boolean = { + isRowOk(grid, row, num) && isColumnOk(grid, column, num) && isSmallBoxOk(grid, row, column, num) + } + + def isRowOk(grid: Array[Array[Int]], row: Int, num: Int): Boolean = { + var isOk = true + breakable { + for (column <- Range(0, 9)) { + if (grid(row)(column) == num) { + isOk = false + break + } + } + } + isOk + } + + def isColumnOk(grid: Array[Array[Int]], column: Int, num: Int): Boolean = { + var isOk = true + breakable { + for (row <- Range(0, 9)) { + if (grid(row)(column) == num) { + isOk = false + break + } + } + } + isOk + } + + def isSmallBoxOk(grid: Array[Array[Int]], row: Int, column: Int, num: Int): Boolean = { + val rowOffSet = (row / 3) * 3 + val columnOffSet = (column / 3) * 3 + var isOk = true + breakable { + for (i <- Range(0, 3)) { + for (j <- Range(0, 3)) { + if (grid(i + rowOffSet)(j + columnOffSet) == num) { + isOk = false + break + } + } + } + } + isOk + } + + def printGrid(grid: Array[Array[Int]]): Unit = { + for (i <- Range(0, 9)) { + if (i % 3 == 0) { + println("-------------------------") + } + for (j <- Range(0, 9)) { + if (j % 3 == 0) { + print("| ") + } + print(grid(i)(j) + " ") + } + println("| ") + + } + println("-------------------------") + } + +} diff --git a/scala/src/main/scala/ch43_topology_sort/GraphTopology.scala b/scala/src/main/scala/ch43_topology_sort/GraphTopology.scala new file mode 100644 index 0000000..c7aaeb5 --- /dev/null +++ b/scala/src/main/scala/ch43_topology_sort/GraphTopology.scala @@ -0,0 +1,100 @@ +package ch43_topology_sort + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer + +class GraphTopology(vertex: Int) { + + //define the graph + val adjacency = new Array[mutable.MutableList[Int]](vertex) + for (i <- Range(0, vertex)) { + adjacency(i) = new mutable.MutableList[Int]() + } + + def addEdge(startIndex: Int, targetIndex: Int) = { + adjacency(startIndex) += targetIndex + } + + def topologySortByKahn(): Array[Int] = { + val seq = new mutable.ArrayBuffer[Int]() + //inDegrees contains all the inDegree for a given node + val inDegrees = new Array[Int](vertex) + for (i <- Range(0, vertex)) { + for (j <- adjacency(i).indices) { + val index = adjacency(i).get(j).get + inDegrees(index) += 1 + } + } + + val queue = new mutable.Queue[Int]() + for (i <- inDegrees.indices) { + if (inDegrees(i) == 0) { + // means there is no inDegree for this node, + // this could be the starting point of the dependency graph + queue += i + } + } + + //start to navigating the graph from the starting point + while (queue.nonEmpty) { + val index = queue.dequeue() + + //push to the result + seq += index + + for (i <- adjacency(index).indices) { + val inDegreeIndex = adjacency(index).get(i).get + inDegrees(inDegreeIndex) -= 1 + + if (inDegrees(inDegreeIndex) == 0) { + queue += inDegreeIndex + } + } + } + + seq.toArray + } + + def topologySortByDFS(): Array[Int] = { + val inverseAdj = new Array[mutable.MutableList[Int]](vertex) + for (i <- Range(0, vertex)) { + inverseAdj(i) = new mutable.MutableList[Int]() + } + + //build the inverse adj + for (i <- Range(0, vertex)) { + for (j <- adjacency(i).indices) { + val index = adjacency(i).get(j).get + inverseAdj(index) += i + } + } + + val visited = new Array[Boolean](vertex) + val seq = new ArrayBuffer[Int]() + for (i <- Range(0, vertex)) { + if (!visited(i)) { + visited(i) = true + //call dfs + seq ++= dfs(i, inverseAdj, visited) + } + } + + seq.toArray + } + + def dfs(index: Int, inverseAdj: Array[mutable.MutableList[Int]], visited: Array[Boolean]): ArrayBuffer[Int] = { + val seq = new ArrayBuffer[Int]() + + for (i <- inverseAdj(index).indices) { + val sourceIndex = inverseAdj(index).get(i).get + if (!visited(sourceIndex)) { + visited(sourceIndex) = true + seq ++= dfs(sourceIndex, inverseAdj, visited) + } + } + seq += index + seq + } +} + + diff --git a/scala/src/test/scala/ch39_back_tracking/BagWeightTest.scala b/scala/src/test/scala/ch39_back_tracking/BagWeightTest.scala new file mode 100644 index 0000000..870754b --- /dev/null +++ b/scala/src/test/scala/ch39_back_tracking/BagWeightTest.scala @@ -0,0 +1,15 @@ +package ch39_back_tracking + +import org.scalatest.FlatSpec + +class BagWeightTest extends FlatSpec { + + behavior of "BagWeightTest" + + it should "calculateMaxWeight" in { + val bagWeight = new BagWeight(5,9) + val maxWeight = bagWeight.calculateMaxWeight(Array(1,2,3,5,6)) + println(maxWeight) + } + +} diff --git a/scala/src/test/scala/ch39_back_tracking/EightQueensTest.scala b/scala/src/test/scala/ch39_back_tracking/EightQueensTest.scala new file mode 100644 index 0000000..03d6e7a --- /dev/null +++ b/scala/src/test/scala/ch39_back_tracking/EightQueensTest.scala @@ -0,0 +1,14 @@ +package ch39_back_tracking + +import org.scalatest.FlatSpec + +class EightQueensTest extends FlatSpec { + + behavior of "EightQueensTest" + + it should "calc8Queues" in { + val eightQueens = new EightQueens() + eightQueens.calc8Queues(0) + } + +} diff --git a/scala/src/test/scala/ch39_back_tracking/NQueensTest.scala b/scala/src/test/scala/ch39_back_tracking/NQueensTest.scala new file mode 100644 index 0000000..e4e91ca --- /dev/null +++ b/scala/src/test/scala/ch39_back_tracking/NQueensTest.scala @@ -0,0 +1,21 @@ +package ch39_back_tracking + +import org.scalatest.FlatSpec + +class NQueensTest extends FlatSpec { + + behavior of "NQueensTest" + + it should "calc8Queues" in { + val eightQueens = new NQueens(8) + eightQueens.calcNQueues(0) + + } + + it should "calc4Queues" in { + val eightQueens = new NQueens(4) + eightQueens.calcNQueues(0) + + } + +} diff --git a/scala/src/test/scala/ch39_back_tracking/SudokuTest.scala b/scala/src/test/scala/ch39_back_tracking/SudokuTest.scala new file mode 100644 index 0000000..878c613 --- /dev/null +++ b/scala/src/test/scala/ch39_back_tracking/SudokuTest.scala @@ -0,0 +1,74 @@ +package ch39_back_tracking + +import org.scalatest.FlatSpec + +class SudokuTest extends FlatSpec { + + behavior of "SudokuTest" + + it should "resolve - 1" in { + val grid = Array( + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0) + ) + val sudoku = new Sudoku() + sudoku.resolve(grid) + } + + it should "resolve - 2" in { + val grid = Array( + Array(0, 0, 7, 2, 5, 6, 4, 0 ,0), + Array(4, 0, 0, 0, 0, 0, 0, 0, 5), + Array(0, 1, 0, 0, 3, 9, 0, 6, 0), + Array(0, 0, 0, 5, 0, 8, 0, 0, 0), + Array(0, 0, 8, 0, 6, 0, 2, 0, 0), + Array(0, 9, 0, 1, 0, 7, 0, 0, 0), + Array(0, 3, 0, 0, 7, 0, 0, 9, 0), + Array(2, 0, 0, 0, 0, 0, 0, 0, 4), + Array(0, 0, 6, 3, 1, 2, 7, 0, 8) + ) + val sudoku = new Sudoku() + sudoku.resolve(grid) + } + + it should "resolve - 3" in { + val grid = Array( + Array(3, 8, 0, 0, 0, 0, 0, 0, 1), + Array(0, 0, 6, 4, 0, 0, 7, 8, 5), + Array(0, 0, 9, 0, 2, 0, 3, 0, 0), + Array(0, 6, 0, 0, 9, 0, 0, 0, 0), + Array(8, 0, 0, 3, 0, 2, 0, 0, 9), + Array(0, 0, 0, 0, 4, 0, 0, 7, 0), + Array(0, 0, 1, 0, 7, 0, 5, 0, 0), + Array(4, 9, 5, 0, 0, 6, 1, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 9, 2) + ) + val sudoku = new Sudoku() + sudoku.resolve(grid) + } + + it should "print grid" in { + val grid = Array( + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0), + Array(0, 0, 0, 0, 0, 0, 0, 0, 0) + ) + + val sudoku = new Sudoku() + sudoku.printGrid(grid) + } + +} diff --git a/scala/src/test/scala/ch43_topology_sort/GraphTopologyTest.scala b/scala/src/test/scala/ch43_topology_sort/GraphTopologyTest.scala new file mode 100644 index 0000000..dfb2432 --- /dev/null +++ b/scala/src/test/scala/ch43_topology_sort/GraphTopologyTest.scala @@ -0,0 +1,120 @@ +package ch43_topology_sort + +import org.scalatest.{FlatSpec, Matchers} + +class GraphTopologyTest extends FlatSpec with Matchers { + + behavior of "GraphTopologyTest" + + /* + a -> b + | | + \|/ \|/ + c -> d -> e + */ + it should "topologySortByKahn - 1" in { + val nodes = Array("a", "b", "c", "d", "e") + val graphTopology = new GraphTopology(nodes.length) + graphTopology.addEdge(0, 1) + graphTopology.addEdge(0, 2) + graphTopology.addEdge(1, 3) + graphTopology.addEdge(2, 3) + graphTopology.addEdge(3, 4) + + val seq = graphTopology.topologySortByKahn() + seq.map(nodes(_)).mkString(",") should equal("a,b,c,d,e") + } + + /* + a -> d --- + | | + \|/ \|/ + e -> c + */ + it should "topologySortByKahn - 2" in { + val nodes = Array("a", "b", "c", "d", "e") + val graphTopology = new GraphTopology(nodes.length) + graphTopology.addEdge(0, 3) + graphTopology.addEdge(3, 4) + graphTopology.addEdge(3, 2) + graphTopology.addEdge(4, 2) + + val seq = graphTopology.topologySortByKahn() + seq.map(nodes(_)).mkString(",") should equal("a,b,d,e,c") + } + + /* + a -> d <- b + | /|\ + \|/ | + e -> c + */ + it should "topologySortByKahn - 3" in { + val nodes = Array("a", "b", "c", "d", "e") + val graphTopology = new GraphTopology(nodes.length) + graphTopology.addEdge(0, 3) + graphTopology.addEdge(3, 4) + graphTopology.addEdge(4, 2) + graphTopology.addEdge(2, 1) + graphTopology.addEdge(1, 3) + + val seq = graphTopology.topologySortByKahn() + seq.map(nodes(_)).mkString(",") should equal("a") + } + + /* + a -> b + | | + \|/ \|/ + c -> d -> e + */ + it should "topologySortByDFS - 1" in { + val nodes = Array("a", "b", "c", "d", "e") + val graphTopology = new GraphTopology(nodes.length) + graphTopology.addEdge(0, 1) + graphTopology.addEdge(0, 2) + graphTopology.addEdge(1, 3) + graphTopology.addEdge(2, 3) + graphTopology.addEdge(3, 4) + + val seq = graphTopology.topologySortByDFS() + seq.map(nodes(_)).mkString(",") should equal("a,b,c,d,e") + } + + /* + a -> d --- + | | + \|/ \|/ + e -> c + */ + it should "topologySortByDFS - 2" in { + val nodes = Array("a", "b", "c", "d", "e") + val graphTopology = new GraphTopology(nodes.length) + graphTopology.addEdge(0, 3) + graphTopology.addEdge(3, 4) + graphTopology.addEdge(3, 2) + graphTopology.addEdge(4, 2) + + val seq = graphTopology.topologySortByDFS() + seq.map(nodes(_)).mkString(",") should equal("a,b,d,e,c") + } + + /* + a -> d <- b + | /|\ + \|/ | + e -> c + */ + it should "topologySortByDFS - 3" in { + val nodes = Array("a", "b", "c", "d", "e") + val graphTopology = new GraphTopology(nodes.length) + graphTopology.addEdge(0, 3) + graphTopology.addEdge(3, 4) + graphTopology.addEdge(4, 2) + graphTopology.addEdge(2, 1) + graphTopology.addEdge(1, 3) + + val seq = graphTopology.topologySortByKahn() + seq.map(nodes(_)).mkString(",") should equal("a") + } +}