├── .gitignore ├── LICENSE ├── README.md ├── ch_0 ├── fib.go ├── fizzbuzz.go └── plans.txt ├── ch_1 ├── 1_AllUnique.go ├── 1_AllUnique_test.go ├── 2_Reverse.go ├── 3_IsPermutation.go ├── 3_IsPermutation_test.go ├── 4_SpaceEncode.go ├── 4_SpaceEncode_test.go ├── 5_Compress.go ├── 5_Compress_test.go ├── 6_RotateImage.go ├── 6_RotateImageNotes.txt ├── 6_RotateImage_test.go ├── 7_ZeroRowCol.go ├── 7_ZeroRowCol_test.go ├── 8_IsRotation.go └── 8_IsRotation_test.go ├── ch_2 ├── 1_RemoveDupes.go ├── 1_RemoveDupes_test.go ├── 2_KthToLast.go ├── 2_KthToLast_test.go ├── 3_DeleteMid.go ├── 3_DeleteMid_test.go ├── 4_Partition.go ├── 4_Partition_test.go ├── 5_AddNumbers.go ├── 5_AddNumbers_test.go ├── 6_DetectLoop.go ├── 6_DetectLoop_test.go ├── 7_IsPalindrome.go ├── 7_IsPalindrome_test.go └── LinkedListUtils.go └── ch_3 ├── 1_ArrayStack.go ├── 2_StackMin.go ├── 3_SetOfStacks.go ├── QueueUtils.go └── StackUtils.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # golang_ctci 2 | Working my way through cracking the coding interview in Go, because I want to learn it 3 | 4 | If you only have time to check out one thing in this repo, 1.6 is the solution I'm most proud of so far. 5 | -------------------------------------------------------------------------------- /ch_0/fib.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | func main() { 10 | var maxItrs, err = strconv.ParseInt(os.Args[len(os.Args)-1], 0, 0) 11 | if err != nil { 12 | panic(err) 13 | } 14 | var fib1, fib2 int64 = 0, 1 15 | fmt.Println(fib1) 16 | fmt.Println(fib2) 17 | for i := 1; int64(i) < maxItrs; i++ { 18 | temp := fib1 + fib2 19 | fib1 = fib2 20 | fib2 = temp 21 | fmt.Println(fib2) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch_0/fizzbuzz.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 1; i <= 100; i++ { 7 | switch { 8 | case i%3 == 0: 9 | fmt.Print("Fizz") 10 | if i%5 == 0 { 11 | fmt.Print("Buzz") 12 | } 13 | case i%5 == 0: 14 | fmt.Print("Buzz") 15 | default: 16 | fmt.Print(i) 17 | } 18 | fmt.Printf("\n") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch_0/plans.txt: -------------------------------------------------------------------------------- 1 | Plans for chapter 0 2 | 3 | Before I get started with any actual questions, I want to make sure I understand go. 4 | 5 | To that end, I'll be writing some trivially simple programs in this dir. 6 | 7 | -Hello World (already done with git setup thanks to https://golang.org/doc/code.html, in a separate location) 8 | -FizzBuzz 9 | -Fibonacci, to some reasonable amount of iterations 10 | -------------------------------------------------------------------------------- /ch_1/1_AllUnique.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | func AllUniqueNaive(s string) bool { 4 | for i := 0; i < len(s); i++ { 5 | for j := i+1; j < len(s); j++ { 6 | if s[i] == s[j] { 7 | return false 8 | } 9 | } 10 | } 11 | return true 12 | } 13 | 14 | func AllUniqueSet(s string) bool { 15 | var set = make(map[rune]bool) 16 | for _, c := range s { 17 | if set[c] { 18 | return false 19 | } 20 | set[c] = true 21 | } 22 | return true 23 | } 24 | -------------------------------------------------------------------------------- /ch_1/1_AllUnique_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "testing" 4 | 5 | func TestAllUnique(t *testing.T) { 6 | cases := []struct { 7 | in string 8 | want bool 9 | }{ 10 | {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", true}, 11 | {"abbc", false}, 12 | {"ABC123ABC123", false}, 13 | } 14 | 15 | for _, c := range cases { 16 | got1 := AllUniqueNaive(c.in) 17 | if got1 != c.want { 18 | t.Errorf("AllUniqueNaive(%q) == %q, want %q", c.in, got1, c.want) 19 | } 20 | got2 := AllUniqueSet(c.in) 21 | if got2 != c.want { 22 | t.Errorf("AllUniqueNaive(%q) == %q, want %q", c.in, got2, c.want) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ch_1/2_Reverse.go: -------------------------------------------------------------------------------- 1 | //1.2 omitted, as it explicitly asks for C/C++, and I already more-or-less solved this when setting up go via the example at https://golang.org/doc/code.html 2 | 3 | package ctci_chapter1 4 | -------------------------------------------------------------------------------- /ch_1/3_IsPermutation.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | func IsPermutation(first, second string) bool { 4 | if len(first) != len(second) { 5 | return false 6 | } 7 | 8 | set1 := make(map[rune]int) 9 | set2 := make(map[rune]int) 10 | for _, c := range first { 11 | set1[c]++ 12 | } 13 | for _, c := range second { 14 | set2[c]++ 15 | } 16 | 17 | if len(set1) != len(set2) { 18 | return false 19 | } 20 | 21 | for k,v := range set1 { 22 | if set2[k] != v { 23 | return false 24 | } 25 | delete(set2, k) 26 | } 27 | 28 | return len(set2) == 0 29 | } 30 | -------------------------------------------------------------------------------- /ch_1/3_IsPermutation_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "testing" 4 | 5 | func TestIsPerm(t *testing.T) { 6 | cases := []struct { 7 | in1 string 8 | in2 string 9 | want bool 10 | }{ 11 | {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxvwutsrqponmlkjihgfedcba", true}, 12 | {"abbc", "cabb", true}, 13 | {"ABC123ABC123", "123123ABCABC", true}, 14 | {"abbcdef", "abccdef", false}, 15 | } 16 | 17 | for _, c := range cases { 18 | got := IsPermutation(c.in1, c.in2) 19 | if got != c.want { 20 | t.Errorf("IsPermutation(%q, %q) == %q, want %q", c.in1, c.in2, got, c.want) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch_1/4_SpaceEncode.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "bytes" 4 | 5 | func SpaceEncode(input string) string { 6 | var buffer bytes.Buffer 7 | var ready,writeSpace = false,false 8 | for _, c := range input { 9 | if c != ' ' { 10 | if writeSpace { 11 | buffer.WriteString("%20") 12 | } 13 | buffer.WriteRune(c) 14 | ready = true 15 | writeSpace = false 16 | } else if ready { 17 | writeSpace = true 18 | } 19 | } 20 | return buffer.String() 21 | } 22 | -------------------------------------------------------------------------------- /ch_1/4_SpaceEncode_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "testing" 4 | 5 | func TestSpaceEncode(t *testing.T) { 6 | cases := []struct { 7 | in string 8 | want string 9 | }{ 10 | {"Hello, World!", "Hello,%20World!"}, 11 | {"abbc", "abbc"}, 12 | {" me ow ", "me%20ow"}, 13 | {"Mr John Smith ", "Mr%20John%20Smith"}, 14 | } 15 | 16 | for _, c := range cases { 17 | got := SpaceEncode(c.in) 18 | if got != c.want { 19 | t.Errorf("SpaceEncode(%q) == %q, want %q", c.in, got, c.want) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch_1/5_Compress.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import ( 4 | "bytes" 5 | "strconv" 6 | ) 7 | 8 | func Compress(input string) string { 9 | var buffer bytes.Buffer 10 | var curRune rune = 0 11 | var curCount = 0 12 | for _, c := range input { 13 | if c != curRune { 14 | if curRune != 0 { 15 | buffer.WriteRune(curRune) 16 | buffer.WriteString(strconv.Itoa(curCount)) 17 | } 18 | curRune = c 19 | curCount = 1 20 | } else { 21 | curCount++ 22 | } 23 | } 24 | buffer.WriteRune(curRune) 25 | buffer.WriteString(strconv.Itoa(curCount)) 26 | 27 | var ret = buffer.String() 28 | if len(ret) < len(input) { 29 | return ret 30 | } 31 | return input 32 | } 33 | -------------------------------------------------------------------------------- /ch_1/5_Compress_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "testing" 4 | 5 | func TestCompress(t *testing.T) { 6 | cases := []struct { 7 | in string 8 | want string 9 | }{ 10 | {"aabcccccaaa","a2b1c5a3"}, 11 | {"abbc", "abbc"}, 12 | {"aaAAAAzuDDDwww", "a2A4z1u1D3w3"}, 13 | } 14 | 15 | for _, c := range cases { 16 | got := Compress(c.in) 17 | if got != c.want { 18 | t.Errorf("SpaceEncode(%q) == %q, want %q", c.in, got, c.want) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch_1/6_RotateImage.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | type coordPair struct { 4 | row int 5 | col int 6 | } 7 | 8 | type itrDef struct { 9 | start int 10 | lim int 11 | dir int 12 | } 13 | 14 | func RotateImage(input [][]int32) [][]int32 { 15 | //new plan: when swapping, set up threads 16 | //each thread comunicates via a channel 17 | //to give next x,y coordinate 18 | //main thread receives these values, then calls swap on them 19 | 20 | quadrantDefs := []coordPair { 21 | {0,0}, 22 | {0,1}, 23 | {1,1}, 24 | {1,0}, 25 | } 26 | 27 | inLen := len(input) 28 | 29 | //now, swap in place: 30 | //q[0],q[1] 31 | //q[0],q[2] 32 | //q[0],q[3] 33 | for q:=1; q < 4; q++ { 34 | c1, c2 := make(chan coordPair), make(chan coordPair) 35 | go quadrantItr(quadrantDefs[0].row, quadrantDefs[0].col, inLen, c1) 36 | go quadrantItr(quadrantDefs[q].row, quadrantDefs[q].col, inLen, c2) 37 | 38 | iterations := int(inLen/2) 39 | iterations *= (iterations+inLen%2) 40 | for i:=0; i < iterations; i++ { 41 | old := <-c1 42 | knew := <-c2 43 | swap(old.row, old.col, knew.row, knew.col, input[:][:]) 44 | } 45 | } 46 | 47 | return input 48 | } 49 | 50 | func quadrantItr(row int, col int, length int, output chan<- coordPair) { 51 | colMajor := (row-col == 0) 52 | defs := make([]itrDef,2) 53 | defs[0] = makeDef(row, length, !colMajor) 54 | defs[1] = makeDef(col, length, colMajor) 55 | 56 | if colMajor { 57 | for j := defs[1].start; j != defs[1].lim; j+=defs[1].dir { 58 | for i := defs[0].start; i != defs[0].lim; i+=defs[0].dir { 59 | output <- coordPair{i, j} 60 | } 61 | } 62 | } else { 63 | for i := defs[0].start; i != defs[0].lim; i+=defs[0].dir { 64 | for j := defs[1].start; j != defs[1].lim; j+=defs[1].dir { 65 | output <- coordPair{i, j} 66 | } 67 | } 68 | } 69 | } 70 | 71 | func makeDef(in int, length int, isMajor bool) itrDef { 72 | var ret itrDef 73 | if in == 0 { 74 | ret.start = 0 75 | ret.lim = int(length/2) 76 | if isMajor { 77 | ret.lim += length%2 78 | } 79 | ret.dir = 1 80 | } else { 81 | ret.start = length-1 82 | ret.lim = int(length/2)-1 83 | if !isMajor { 84 | ret.lim += length%2 85 | } 86 | ret.dir = -1 87 | } 88 | return ret 89 | } 90 | 91 | func swap(x1 int, y1 int, x2 int, y2 int, array [][]int32) { 92 | array[x1][y1] = array[x1][y1] ^ array[x2][y2] 93 | array[x2][y2] = array[x1][y1] ^ array[x2][y2] 94 | array[x1][y1] = array[x1][y1] ^ array[x2][y2] 95 | } 96 | -------------------------------------------------------------------------------- /ch_1/6_RotateImageNotes.txt: -------------------------------------------------------------------------------- 1 | Consistent row/col references: 2 | I've been having issues conflating my rows/columns, so this will be the reference for how it goes. 3 | 4 | Row comes first, then col. 5 | 6 | Map of 3x3: 7 | 00 01 02 8 | 10 11 12 9 | 20 21 22 10 | 11 | So when swapping quadrants, I'll do it like this: 12 | -swap 00 with 01 13 | -swap 00 with 11 14 | -swap 00 with 10 15 | -to handle odd numbers, I'll designate one axis as "major", which will go one further to cover the midpoint 16 | -00 and 11 are col major, 01 and 10 are row major 17 | 18 | -so, given the above 3X3, I'll swap like this: 19 | -first: quad 00 with 01 20 | -source: {00 01} 21 | -col major, 1x2 grid 22 | -dest: {02 12} 23 | -row major, 2x1 grid 24 | -result after swap: 25 | 02 12 00 26 | 10 11 01 27 | 20 21 22 28 | -second: quad 00 with quad 11 29 | -source: {02 12} col major 30 | -dest: {22 21} col major 31 | -result: 32 | 22 21 00 33 | 10 11 01 34 | 20 12 02 35 | -third: quad 00 with quad 10 36 | -source: {22 21} 37 | -dest: {20 10} 38 | -result: 39 | 20 10 00 40 | 21 11 01 41 | 22 12 02 42 | 43 | Boom, the input has been rotated 90 degrees in-place. 44 | From here on, now more references to "x" or "y", that's confusing things. "row" and "col" instead. 45 | 46 | Quad defs: 47 | -sum to binary 0 (00 and 11) - col major 48 | -else row major 49 | -if size of inpt grid %2 == 0, quads are square not rectangular 50 | -row/col 0: start at 0, go up to mid 51 | -else row/col 1: start at max, go down to mid 52 | -whichever of row or col is major is outer iteration loop 53 | -------------------------------------------------------------------------------- /ch_1/6_RotateImage_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import ( 4 | "testing" 5 | "fmt" 6 | ) 7 | 8 | func TestRotate(t *testing.T) { 9 | cases := []struct { 10 | in [][]int32 11 | want [][]int32 12 | }{ 13 | { 14 | [][]int32 { 15 | {0,1,2,3}, 16 | {4,5,6,7}, 17 | {8,9,10,11}, 18 | {12,13,14,15}, 19 | }, 20 | [][]int32 { 21 | {12,8,4,0}, 22 | {13,9,5,1}, 23 | {14,10,6,2}, 24 | {15,11,7,3}, 25 | }, 26 | }, 27 | { 28 | [][]int32 { 29 | {1,2,3}, 30 | {4,5,6}, 31 | {7,8,9}, 32 | }, 33 | [][]int32 { 34 | {7,4,1}, 35 | {8,5,2}, 36 | {9,6,3}, 37 | }, 38 | }, 39 | } 40 | 41 | for _, c := range cases { 42 | got := RotateImage(c.in) 43 | if sliceEqual32(got[:][:], c.want[:][:]) == false { 44 | t.Errorf("Error! Results follow") 45 | for i := 0; i < len(got); i++ { 46 | fmt.Println(got[i]) 47 | } 48 | for i := 0; i < len(c.want); i++ { 49 | fmt.Println(c.want[i]) 50 | } 51 | } 52 | } 53 | } 54 | 55 | func sliceEqual32(a [][]int32, b [][]int32) bool { 56 | for i := 0; i < len(a); i++ { 57 | for j := 0; j < len(a); j++ { 58 | if a[i][j] != b[i][j] { 59 | return false 60 | } 61 | } 62 | } 63 | return true 64 | } 65 | -------------------------------------------------------------------------------- /ch_1/7_ZeroRowCol.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | func ZeroRowCol(input [][]int) [][]int { 4 | //first thought: 2-pass, use some extra memory 5 | n := len(input) 6 | m := len(input[0]) 7 | 8 | var rowZeros = make([]bool, n) 9 | var colZeros = make([]bool, m) 10 | for i := 0; i < n; i++ { 11 | for j := 0; j < m; j++ { 12 | if input[i][j] == 0 { 13 | rowZeros[i] = true 14 | colZeros[j] = true 15 | } 16 | } 17 | } 18 | 19 | for i := 0; i < n; i++ { 20 | for j := 0; j < m; j++ { 21 | if rowZeros[i] || colZeros[j] { 22 | input[i][j] = 0 23 | } 24 | } 25 | } 26 | 27 | return input 28 | } 29 | -------------------------------------------------------------------------------- /ch_1/7_ZeroRowCol_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import ( 4 | "testing" 5 | "fmt" 6 | ) 7 | 8 | func TestZeroRowCol(t *testing.T) { 9 | cases := []struct { 10 | in [][]int 11 | want [][]int 12 | }{ 13 | { 14 | [][]int { 15 | {0,1,2,3}, 16 | {4,5,6,7}, 17 | {8,9,0,11}, 18 | {12,13,14,15}, 19 | }, 20 | [][]int { 21 | {0,0,0,0}, 22 | {0,5,0,7}, 23 | {0,0,0,0}, 24 | {0,13,0,15}, 25 | }, 26 | }, 27 | { 28 | [][]int { 29 | {1,2,3}, 30 | {4,0,6}, 31 | {7,8,9}, 32 | }, 33 | [][]int { 34 | {1,0,3}, 35 | {0,0,0}, 36 | {7,0,9}, 37 | }, 38 | }, 39 | } 40 | 41 | for _, c := range cases { 42 | got := ZeroRowCol(c.in) 43 | if sliceEqual(got[:][:], c.want[:][:]) == false { 44 | t.Errorf("Error! Results follow") 45 | for i := 0; i < len(got); i++ { 46 | fmt.Println(got[i]) 47 | } 48 | for i := 0; i < len(c.want); i++ { 49 | fmt.Println(c.want[i]) 50 | } 51 | } 52 | } 53 | } 54 | 55 | func sliceEqual(a [][]int, b [][]int) bool { 56 | for i := 0; i < len(a); i++ { 57 | for j := 0; j < len(a); j++ { 58 | if a[i][j] != b[i][j] { 59 | return false 60 | } 61 | } 62 | } 63 | return true 64 | } 65 | -------------------------------------------------------------------------------- /ch_1/8_IsRotation.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "strings" 4 | 5 | //note: I'll be using strings.Contains() as my 'isSubstring' method as described in the book 6 | func IsRotation(in1 string, in2 string) bool { 7 | if len(in1) != len(in2) { 8 | return false 9 | } 10 | var temp = in1+in1 11 | return strings.Contains(temp, in2) 12 | } 13 | -------------------------------------------------------------------------------- /ch_1/8_IsRotation_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter1 2 | 3 | import "testing" 4 | 5 | func TestIsRotation(t *testing.T) { 6 | cases := []struct { 7 | in1 string 8 | in2 string 9 | want bool 10 | }{ 11 | {"Hello, World!", "World!Hello, ", true}, 12 | {"erbottlewat","waterbottle", true}, 13 | {"meowmeowmeow", "meowmeow", false}, 14 | {"abcd", "efgh", false}, 15 | {"","",true}, 16 | } 17 | 18 | for _, c := range cases { 19 | got := IsRotation(c.in1, c.in2) 20 | if got != c.want { 21 | t.Errorf("IsRotation(%q,%q) == %q, want %q", c.in1, c.in2, got, c.want) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch_2/1_RemoveDupes.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | //this approach uses no extra space, but runs in O(n^2) time 4 | func (n *Node) RemoveDupesNaive() { 5 | for cur := n; cur != nil; cur = cur.next { 6 | for inner := cur; inner.next != nil;{ 7 | if cur.data == inner.next.data { 8 | inner.next = inner.next.next 9 | } else { 10 | inner = inner.next 11 | } 12 | } 13 | } 14 | } 15 | 16 | //this solution uses O(n) space, and runs in O(n) time 17 | func (n *Node) RemoveDupes() { 18 | datas := make(map[int]bool) 19 | datas[n.data] = true 20 | for cur := n; cur.next != nil; { 21 | if datas[cur.next.data] { 22 | cur.next = cur.next.next 23 | } else { 24 | datas[cur.next.data] = true 25 | cur = cur.next 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ch_2/1_RemoveDupes_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestRemoveDupes(t *testing.T) { 6 | cases := []struct { 7 | in []int 8 | want []int 9 | }{ 10 | {[]int {1,2,2,3,4,2,3,6,7,2,4,1,8}, []int {1,2,3,4,6,7,8}}, 11 | {[]int {123,231,432,10,123,123,123,10}, []int {123,231,432,10}}, 12 | } 13 | 14 | for _, c := range cases { 15 | inNode, wantNode := NodeSetupSmart(c.in), NodeSetupSmart(c.want) 16 | priorString := inNode.ListString() 17 | inNode.RemoveDupesNaive() 18 | if !inNode.ListEquals(wantNode) { 19 | t.Errorf("RemoveDupesNaive(%q) == %q, want %q", priorString, inNode.ListString(), wantNode.ListString()) 20 | } 21 | 22 | inNode = NodeSetupSmart(c.in) 23 | priorString = inNode.ListString() 24 | inNode.RemoveDupes() 25 | if !inNode.ListEquals(wantNode) { 26 | t.Errorf("RemoveDupes(%q) == %q, want %q", priorString, inNode.ListString(), wantNode.ListString()) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch_2/2_KthToLast.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | func (n *Node) KthToLast(k int) int { 4 | //place 'cur' k places in front of n 5 | cur := n 6 | for i := 1; cur != nil && i < k; cur, i = cur.next, i+1 {} 7 | 8 | //panic if needed 9 | if cur == nil { 10 | panic("List shorted than provided k") 11 | } 12 | 13 | //now just iterate to the end 14 | for ; cur.next != nil; cur, n = cur.next, n.next {} 15 | 16 | return n.data 17 | } -------------------------------------------------------------------------------- /ch_2/2_KthToLast_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestKthToLast(t *testing.T) { 6 | cases := []struct { 7 | inList []int 8 | inK int 9 | want int 10 | }{ 11 | {[]int {1,2,2,3,4,2,3,6,7,2,4,1,8}, 3, 4}, 12 | {[]int {1,2,2,3,4,2,3,6,7,2,4,1,8}, 1, 8}, 13 | {[]int {1,2,2,3,4,2,3,6,7,2,4,1,8}, 13, 1}, 14 | {[]int {123,231,432,10,123,123,123,10}, 5, 10}, 15 | } 16 | 17 | for _, c := range cases { 18 | inNode := NodeSetupSmart(c.inList) 19 | got := inNode.KthToLast(c.inK) 20 | if got != c.want { 21 | t.Errorf("method KthToLast(%q) on list %q == %q, want %q", c.inK, inNode.ListString(), got, c.want) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch_2/3_DeleteMid.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | func (n *Node) DeleteMid() { 4 | if n == nil || n.next == nil { 5 | panic("Can't call DeleteMid on a final or nonexistent Node") 6 | } 7 | n.data = n.next.data 8 | n.next = n.next.next 9 | } -------------------------------------------------------------------------------- /ch_2/3_DeleteMid_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestDeleteMid(t *testing.T) { 6 | cases := []struct { 7 | in []int 8 | inDel int //number of cur->next iterations to use before calling DeleteMid() 9 | want []int 10 | }{ 11 | {[]int {1,2,2,3,4}, 3, []int {1,2,2,4}}, 12 | {[]int {1,2,2,3,4}, 0, []int {2,2,3,4}}, 13 | } 14 | 15 | for _, c := range cases { 16 | inNode, wantNode := NodeSetupSmart(c.in), NodeSetupSmart(c.want) 17 | priorString := inNode.ListString() 18 | 19 | cur := &inNode 20 | //deliberately excluding a check for cur == nil, that's a panic that test cases should avoid hitting on their own 21 | for i := 0; i < c.inDel; cur, i = cur.next, i+1 {} 22 | cur.DeleteMid() 23 | if !inNode.ListEquals(wantNode) { 24 | t.Errorf("DeleteMid(%q, %d) == %q, want %q", priorString, c.inDel, inNode.ListString(), wantNode.ListString()) 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ch_2/4_Partition.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | func (n *Node) Partition(k int) Node { 4 | var low, high, uninit Node 5 | for ; n != nil; n = n.next { 6 | if n.data < k { 7 | if low == uninit { 8 | low = Node{nil, n.data} 9 | } else { 10 | low.Append(n.data) 11 | } 12 | } else { 13 | if high == uninit { 14 | high = Node{nil, n.data} 15 | } else { 16 | high.Append(n.data) 17 | } 18 | } 19 | } 20 | 21 | cur := &low 22 | for ; cur.next != nil; cur = cur.next {} 23 | cur.next = &high 24 | return low 25 | } -------------------------------------------------------------------------------- /ch_2/4_Partition_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestPartition(t *testing.T) { 6 | cases := []struct { 7 | in []int 8 | k int 9 | }{ 10 | {[]int {10,1,9,2,8,3,7,4,6,5}, 5}, 11 | {[]int {1,2,2,3,4,2,6}, 3}, 12 | } 13 | 14 | for _, c := range cases { 15 | inNode := NodeSetupSmart(c.in) 16 | cur := &inNode 17 | gotNode := cur.Partition(c.k) 18 | if !gotNode.VerifyPartition(c.k) { 19 | t.Errorf("Partition(%q, %d) == %q", inNode.ListString(), c.k, gotNode.ListString()) 20 | } 21 | } 22 | } 23 | 24 | func (oldNode *Node) VerifyPartition(k int) bool { 25 | cur := oldNode 26 | for ; cur != nil && cur.data < k; cur = cur.next {} 27 | for ; cur != nil; cur = cur.next { 28 | if cur.data < k { 29 | return false 30 | } 31 | } 32 | return true 33 | } -------------------------------------------------------------------------------- /ch_2/5_AddNumbers.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | func AddNumbersOnesFirst(a Node, b Node) Node { 4 | carry := 0 5 | ret := Node{nil, -1} 6 | aPtr, bPtr := &a, &b 7 | for ; aPtr != nil && bPtr != nil; aPtr, bPtr = aPtr.next, bPtr.next { 8 | sum := aPtr.data + bPtr.data + carry 9 | if sum > 9 { 10 | sum %= 10 11 | carry = 1 12 | } else { 13 | carry = 0 14 | } 15 | if ret.data == -1 { 16 | ret.data = sum 17 | } else { 18 | ret.AppendToTail(sum) 19 | } 20 | } 21 | 22 | //only 1 of these next 2 loops may run, do to condition of first for loop 23 | for ; aPtr != nil; aPtr = aPtr.next { 24 | sum := aPtr.data + carry 25 | if sum > 9 { 26 | sum %= 10 27 | carry = 1 28 | } else { 29 | carry = 0 30 | } 31 | ret.AppendToTail(sum) 32 | } 33 | 34 | for ; bPtr != nil; bPtr = bPtr.next { 35 | sum := bPtr.data + carry 36 | if sum > 9 { 37 | sum %= 10 38 | carry = 1 39 | } else { 40 | carry = 0 41 | } 42 | ret.AppendToTail(sum) 43 | } 44 | 45 | if carry != 0 { 46 | ret.AppendToTail(carry) 47 | } 48 | 49 | return ret 50 | } 51 | 52 | func AddNumbersOnesLast(a Node, b Node) Node { 53 | //this is kind of cheating, but if I were given the problems in this order, this is how I would solve them 54 | //since I already have a working AddOnesFirst, simply reversing the list is easier/more eficient use of my dev time than trying to sort out all the details of OnesLast 55 | //but if I were to do that, it would involve some way of passing the 2 lists into goroutines, and having those pass back the partial sums in ones first order 56 | aRev := recurseReverse(a) 57 | bRev := recurseReverse(b) 58 | return recurseReverse(AddNumbersOnesFirst(aRev, bRev)) 59 | } 60 | 61 | func recurseReverse(n Node) Node { 62 | if n.next == nil { 63 | return n 64 | } 65 | ret := recurseReverse(*(n.next)) 66 | 67 | //this causes recurseReverse to run in O(n^2), I'm banking on n being small enough to not matter much (# of digits) 68 | ret.AppendToTail(n.data) 69 | return ret 70 | } -------------------------------------------------------------------------------- /ch_2/5_AddNumbers_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestAddNumbers(t *testing.T) { 6 | cases := []struct { 7 | inA []int 8 | inB []int 9 | want []int 10 | }{ 11 | {[]int {7,1,6}, []int {5,9,2}, []int {2,1,9}}, 12 | {[]int {9,1,1}, []int {1,9,9}, []int {0,1,1,1}}, 13 | {[]int {5,4}, []int {5,5,9,1}, []int {0,0,0,2}}, 14 | } 15 | 16 | for _, c := range cases { 17 | inNodeA, inNodeB, wantNode := NodeSetupSmart(c.inA), NodeSetupSmart(c.inB), NodeSetupSmart(c.want) 18 | got1 := AddNumbersOnesFirst(inNodeA, inNodeB) 19 | if !got1.ListEquals(wantNode) { 20 | t.Errorf("AddNumbersOnesFirst(%q, %q) == %q, want %q", inNodeA.ListString(), inNodeB.ListString(), got1.ListString(), wantNode.ListString()) 21 | } 22 | 23 | Reverse(&c.inA) 24 | Reverse(&c.inB) 25 | Reverse(&c.want) 26 | inNodeA, inNodeB, wantNode = NodeSetupSmart(c.inA), NodeSetupSmart(c.inB), NodeSetupSmart(c.want) 27 | got2 := AddNumbersOnesLast(inNodeA, inNodeB) 28 | if !got2.ListEquals(wantNode) { 29 | t.Errorf("AddNumbersOnesLast(%q, %q) == %q, want %q", inNodeA.ListString(), inNodeB.ListString(), got2.ListString(), wantNode.ListString()) 30 | } 31 | } 32 | } 33 | 34 | func Reverse(rPtr *[]int) { 35 | r := *rPtr 36 | for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 37 | r[i], r[j] = r[j], r[i] 38 | } 39 | } -------------------------------------------------------------------------------- /ch_2/6_DetectLoop.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | /* 4 | The approach here: I use the standard fast-slow runner technique to detect a looped list 5 | To find the beginning, I make use of the following two facts I believe to be true: 6 | -if fast and slow meet, the node they meet at is in the loop 7 | -if I remove* the "beginning" of the loop, there will no longer be a loop 8 | -where 'remove' means 'skip over it in the beginning of the loop, and point the end-of-loop instance to nil' 9 | */ 10 | 11 | func DetectLoop(n Node) *Node { 12 | if n.next == nil { 13 | panic("Can't find loops in list of length 1") 14 | } 15 | var slow, fast, prevS *Node = &n, n.next, nil 16 | for ; slow != fast && fast != nil && fast.next != nil; prevS, slow, fast = slow, slow.next, fast.next.next {} 17 | if fast == nil || fast.next == nil { 18 | //this means we reached the end, and there are no loops 19 | return nil 20 | } else { 21 | //remove slow node, if this "fixes" the loop we've found our start point 22 | prevS.next = slow.next 23 | fast.next = nil 24 | possibleRet := DetectLoop(n) 25 | if possibleRet == nil { 26 | return slow 27 | } else { 28 | return possibleRet 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /ch_2/6_DetectLoop_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestDetectLoop(t *testing.T) { 6 | cases := []struct { 7 | in []int 8 | loopPoint int //zero-indexed, which node tail points to. This is also the 'data' of the desired return Node 9 | }{ 10 | {[]int {1,2,3,4,5}, 1}, 11 | {[]int {1,2,3,4,5}, 2}, 12 | {[]int {0,9,8,7,6,5,4,3,2,1,10,345,35,123,765,234,765}, 11}, 13 | } 14 | 15 | for _, c := range cases { 16 | inNode := NodeSetupSmart(c.in) 17 | priorString := inNode.ListString() //so ListString doesn't explode later 18 | inNode.CreateLoop(c.loopPoint) 19 | got := DetectLoop(inNode) 20 | if got.data != c.in[c.loopPoint] { 21 | t.Errorf("DetectLoop(%q %d) == %d, want %d", priorString, c.in[c.loopPoint], got.data, c.in[c.loopPoint]) 22 | } 23 | } 24 | } 25 | 26 | func (oldNode *Node) CreateLoop (loopPoint int) { 27 | var loopStart, cur *Node = nil, oldNode 28 | for i := 0; cur.next != nil; cur, i = cur.next, i+1 { 29 | if i == loopPoint { 30 | loopStart = cur 31 | } 32 | } 33 | 34 | if loopStart == nil { 35 | panic("Reached end of list before loopPoint") 36 | } 37 | 38 | cur.next = loopStart 39 | } -------------------------------------------------------------------------------- /ch_2/7_IsPalindrome.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | func (oldNode *Node) IsPalindrome() bool { 4 | //on review from the book, I could have done this better 5 | //I like their "slow-fast to find halfway point, make a stack up to there and continue to check front half vs back" approach 6 | //this solution of mine runs in O(n^2) time thanks to recurseReverse, and O(n) space thanks to constructing a copy of the list 7 | revOld := recurseReverse(*oldNode) 8 | for old, knew := oldNode, &revOld; old != nil && knew != nil; old, knew = old.next, knew.next { 9 | if old.data != knew.data { 10 | return false 11 | } 12 | } 13 | return true 14 | } -------------------------------------------------------------------------------- /ch_2/7_IsPalindrome_test.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import "testing" 4 | 5 | func TestIsPalindrome(t *testing.T) { 6 | cases := []struct { 7 | in []int 8 | want bool 9 | }{ 10 | {[]int {1,2,1,1,3,4,4,3,1,1,2,1}, true}, 11 | {[]int {1,2,1,1,3,4,5,4,3,1,1,2,1}, true}, 12 | {[]int {1,2,1,1,3,4,4,3,2,1}, false}, 13 | {[]int {1,2,1,1,3,4,4,3,1,1,2}, false}, 14 | {[]int {1,2,1,1,3,4,3,3,1,1,2,1}, false}, 15 | } 16 | 17 | for _, c := range cases { 18 | inNode := NodeSetupSmart(c.in) 19 | got := inNode.IsPalindrome() 20 | if got != c.want { 21 | t.Errorf("IsPalindrome(%q) == %t, want %t", inNode.ListString(), got, c.want) 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /ch_2/LinkedListUtils.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter2 2 | 3 | import ( 4 | "bytes" 5 | "strconv" 6 | ) 7 | 8 | //a utility linked list, for use with all of the chapter 2 questions 9 | type Node struct { 10 | next *Node 11 | data int 12 | } 13 | 14 | //exporting accessors for use in later chapters 15 | func (n Node) Next() *Node { 16 | return n.next 17 | } 18 | 19 | func (n Node) Data() int { 20 | return n.data 21 | } 22 | 23 | func CreateNode(next *Node, data int) Node{ 24 | return Node{next, data} 25 | } 26 | 27 | //and one setter too 28 | func (n *Node) SetNext(newNext *Node) { 29 | n.next = newNext 30 | } 31 | 32 | func (oldNode *Node) Append(newData int) { 33 | newNode := Node{nil, newData} 34 | newNode.next = oldNode.next 35 | oldNode.next = &newNode 36 | } 37 | 38 | func (oldNode *Node) AppendToTail(newData int) { 39 | newNode := Node{nil, newData} 40 | n := oldNode 41 | for ; n.next != nil; n = n.next { 42 | } 43 | n.next = &newNode 44 | } 45 | 46 | func NodeSetup(input []int) Node { 47 | if len(input) <= 0 { 48 | panic("need to have elements to create linked list") 49 | } 50 | newNode := Node{nil, input[0]} 51 | for i:=1; i < len(input); i++ { 52 | newNode.AppendToTail(input[i]) 53 | } 54 | return newNode 55 | } 56 | 57 | //avoids iterating over the entire list for each addition, lowering the runtime from O(n^2) to O(n) 58 | func NodeSetupSmart(input []int) Node { 59 | if len(input) <= 0 { 60 | panic("need to have elements to create linked list") 61 | } 62 | newNode := Node{nil, input[0]} 63 | curNode := &newNode 64 | for i:=1; i < len(input); i++ { 65 | curNode.Append(input[i]) 66 | curNode = curNode.next 67 | } 68 | return newNode 69 | } 70 | 71 | func (oldNode Node) ListEquals(comp Node) bool { 72 | a, b := &oldNode, &comp 73 | for ; a != nil && b != nil; a, b = a.next, b.next{ 74 | if a.data != b.data { 75 | return false 76 | } 77 | } 78 | return a == nil && b == nil 79 | } 80 | 81 | func (oldNode Node) ListString() string { 82 | var buffer bytes.Buffer 83 | buffer.WriteRune(' ') 84 | for i := &oldNode; i != nil; i = i.next { 85 | buffer.WriteString(strconv.Itoa(i.data)) 86 | buffer.WriteRune(' ') 87 | } 88 | return buffer.String() 89 | } -------------------------------------------------------------------------------- /ch_3/1_ArrayStack.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter3 2 | 3 | type ArrayStack struct { 4 | data [1002]int //chosen to be a reasonably large divisible by 3 size 5 | topDex [3]int 6 | lenData, numSubs, subLen int 7 | } 8 | 9 | func (aStack *ArrayStack) Pop(subStack int) int { 10 | aStack.BasicChecks(subStack) 11 | 12 | min := aStack.subLen*subStack 13 | if aStack.topDex[subStack] < min { 14 | panic("stack underflow") 15 | } 16 | 17 | aStack.topDex[subStack]-- 18 | return aStack.data[aStack.topDex[subStack+1]] 19 | } 20 | 21 | func (aStack *ArrayStack) Push(subStack, newData int) { 22 | aStack.BasicChecks(subStack) 23 | 24 | max := (aStack.subLen*(subStack+1)) 25 | if aStack.topDex[subStack] >= max { 26 | panic("stack overflow") 27 | } 28 | 29 | aStack.topDex[subStack]++ 30 | aStack.data[aStack.topDex[subStack]] = newData 31 | } 32 | 33 | func (aStack *ArrayStack) BasicChecks(i int) { 34 | if aStack.subLen == 0 { 35 | aStack.Setup() 36 | } 37 | if i > aStack.numSubs { 38 | panic("Index out of range, there are 3 substacks per ArrayStack") 39 | } 40 | } 41 | 42 | func (aStack *ArrayStack) Setup() { 43 | aStack.lenData, aStack.numSubs = len(aStack.data), len(aStack.topDex) 44 | aStack.subLen = aStack.lenData/aStack.numSubs 45 | } -------------------------------------------------------------------------------- /ch_3/2_StackMin.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter3 2 | 3 | //a stack which tracks min, with push(), pop() and min() all operating in O(1) 4 | type StackWithMin struct { 5 | top *StackNode 6 | } 7 | 8 | type StackNode struct { 9 | next *StackNode 10 | data int 11 | min int 12 | } 13 | 14 | func (stack *StackWithMin) Pop() int { 15 | if stack.top != nil { 16 | ret := stack.top.data 17 | stack.top = stack.top.next 18 | return ret 19 | } 20 | panic("can't Pop() on an empty stack") 21 | } 22 | 23 | func (stack *StackWithMin) Push(newData int) { 24 | newMin := stack.top.min 25 | if newData < newMin { 26 | newMin = newData 27 | } 28 | newTop := StackNode{stack.top, newData, newMin} 29 | stack.top = &newTop 30 | } 31 | 32 | func (stack *StackWithMin) Min() int { 33 | return stack.top.min 34 | } 35 | 36 | func (stack *StackWithMin) Peek() int { 37 | return stack.top.data 38 | } 39 | 40 | //on review - this could have been more space efficient by allocating a second stack, and using that to track the mins as they change 41 | //this solution is simple and readable though, so in the absence of other constraints I'm OK with it -------------------------------------------------------------------------------- /ch_3/3_SetOfStacks.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter3 2 | 3 | //a set of stacks, as outlined in problem 3.3 4 | type SetOfStacks struct { 5 | top *StackWithSize 6 | } 7 | 8 | type StackWithSize struct { 9 | innerStack *Stack 10 | next *StackWithSize 11 | size int 12 | } 13 | 14 | //intentionally using a very low value for testing 15 | var SetOfStacksCapacity int = 5 16 | 17 | //StackWithSize.Pop, return stack.Pop() and decrement size 18 | func (stack *StackWithSize) Pop() int { 19 | stack.size-- 20 | return stack.innerStack.Pop() 21 | } 22 | 23 | //SetOfStacks.Pop(), call StackWithSize.Pop() and update top if size == 0 after 24 | func (stack *SetOfStacks) Pop() int { 25 | if stack.top != nil { 26 | ret := stack.top.innerStack.Pop() 27 | if stack.top.size == 0 { 28 | stack.top = stack.top.next 29 | } 30 | return ret 31 | } 32 | panic("can't Pop() on an empty stack") 33 | } 34 | 35 | //same with Push for both data structures 36 | func (stack *StackWithSize) Push(newData int) { 37 | stack.innerStack.Push(newData) 38 | stack.size++ 39 | } 40 | 41 | func (stack *SetOfStacks) Push(newData int) { 42 | if stack.top == nil || stack.top.size == SetOfStacksCapacity { 43 | newTop := StackWithSize{&Stack{nil}, stack.top, 1} 44 | stack.top = &newTop 45 | } 46 | stack.top.Push(newData) 47 | } -------------------------------------------------------------------------------- /ch_3/QueueUtils.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter3 2 | 3 | import "golang_ctci/ch_2" 4 | 5 | //a utility Queue, for use with chapter 3 questions 6 | type Queue struct { 7 | first, last *ctci_chapter2.Node 8 | } 9 | 10 | func (q *Queue) Enqueue(newData int) { 11 | knew := ctci_chapter2.CreateNode(nil, newData) 12 | if q.first == nil { 13 | q.last = &knew 14 | q.first = q.last 15 | } else { 16 | q.last.SetNext(&knew) 17 | q.last = q.last.Next() 18 | } 19 | } 20 | 21 | func (q *Queue) Dequeue() int { 22 | if q.first != nil { 23 | ret := q.first.Data() 24 | q.first = q.first.Next() 25 | if q.first == nil { q.last = nil } //empty Queue 26 | return ret 27 | } 28 | panic("Queue is empty") 29 | } -------------------------------------------------------------------------------- /ch_3/StackUtils.go: -------------------------------------------------------------------------------- 1 | package ctci_chapter3 2 | 3 | import "golang_ctci/ch_2" 4 | 5 | //a utility Stack, for use with chapter 3 questions 6 | type Stack struct { 7 | top *ctci_chapter2.Node 8 | } 9 | 10 | func (stack *Stack) Pop() int { 11 | if stack.top != nil { 12 | ret := stack.top.Data() 13 | stack.top = stack.top.Next() 14 | return ret 15 | } 16 | panic("can't Pop() on an empty stack") 17 | } 18 | 19 | func (stack *Stack) Push(newData int) { 20 | newTop := ctci_chapter2.CreateNode(stack.top, newData) 21 | stack.top = &newTop 22 | } 23 | 24 | func (stack *Stack) Peek() int { 25 | return stack.top.Data() 26 | } --------------------------------------------------------------------------------