├── .gitignore ├── LICENSE ├── README.md ├── cpp ├── basic │ ├── main.cpp │ ├── sort.h │ └── util.h ├── concurrent │ ├── blocking_queue.h │ └── main.cpp └── leetcode │ ├── 1.两数之和.cpp │ ├── 101.对称二叉树.cpp │ ├── 102.二叉树的层序遍历.cpp │ ├── 105.从前序与中序遍历序列构造二叉树.cpp │ ├── 108.将有序数组转换为二叉搜索树.cpp │ ├── 109.有序链表转换二叉搜索树.cpp │ ├── 11.盛最多水的容器.cpp │ ├── 120.三角形最小路径和.cpp │ ├── 121.买卖股票的最佳时机.cpp │ ├── 123.买卖股票的最佳时机-iii.cpp │ ├── 128.最长连续序列.cpp │ ├── 134.加油站.cpp │ ├── 135.分发糖果.cpp │ ├── 136.只出现一次的数字.cpp │ ├── 146.lru-缓存.cpp │ ├── 15.三数之和.cpp │ ├── 152.乘积最大子数组.cpp │ ├── 155.最小栈.cpp │ ├── 16.最接近的三数之和.cpp │ ├── 174.地下城游戏.cpp │ ├── 179.最大数.cpp │ ├── 19.删除链表的倒数第-n-个结点.cpp │ ├── 198.打家劫舍.cpp │ ├── 2.两数相加.cpp │ ├── 207.课程表.cpp │ ├── 208.实现-trie-前缀树.cpp │ ├── 209.长度最小的子数组.cpp │ ├── 210.课程表-ii.cpp │ ├── 211.添加与搜索单词-数据结构设计.cpp │ ├── 22.括号生成.cpp │ ├── 23.合并k个升序链表.cpp │ ├── 238.除自身以外数组的乘积.cpp │ ├── 239.滑动窗口最大值.cpp │ ├── 25.k-个一组翻转链表.cpp │ ├── 279.完全平方数.cpp │ ├── 283.移动零.cpp │ ├── 297.二叉树的序列化与反序列化.cpp │ ├── 3.无重复字符的最长子串.cpp │ ├── 300.最长递增子序列.cpp │ ├── 31.下一个排列.cpp │ ├── 33.搜索旋转排序数组.cpp │ ├── 34.在排序数组中查找元素的第一个和最后一个位置.cpp │ ├── 39.组合总和.cpp │ ├── 4.寻找两个正序数组的中位数.cpp │ ├── 407.接雨水-ii.cpp │ ├── 41.缺失的第一个正数.cpp │ ├── 42.接雨水.cpp │ ├── 45.跳跃游戏-ii.cpp │ ├── 46.全排列.cpp │ ├── 5.最长回文子串.cpp │ ├── 51.n-皇后.cpp │ ├── 53.最大子数组和.cpp │ ├── 56.合并区间.cpp │ ├── 60.排列序列.cpp │ ├── 62.不同路径.cpp │ ├── 63.不同路径-ii.cpp │ ├── 68.文本左右对齐.cpp │ ├── 72.编辑距离.cpp │ ├── 74.搜索二维矩阵.cpp │ ├── 75.颜色分类.cpp │ ├── 76.最小覆盖子串.cpp │ ├── 77.组合.cpp │ ├── 78.子集.cpp │ ├── 79.单词搜索.cpp │ ├── 80.删除有序数组中的重复项-ii.cpp │ ├── 81.搜索旋转排序数组-ii.cpp │ ├── 84.柱状图中最大的矩形.cpp │ ├── 85.最大矩形.cpp │ └── 94.二叉树的中序遍历.cpp ├── go ├── basic │ ├── array │ │ └── ringbuf.go │ ├── cache │ │ ├── lfu.go │ │ ├── lfu_test.go │ │ ├── lru.go │ │ └── lru_test.go │ ├── concurrency │ │ ├── alternate.go │ │ ├── concurrency_test.go │ │ ├── linked_queue.go │ │ ├── once.go │ │ └── singleton.go │ ├── dp │ │ └── dp.go │ ├── heap │ │ ├── heap.go │ │ ├── heap_example_test.go │ │ └── heap_test.go │ ├── list │ │ ├── link_list.go │ │ ├── link_list_operate.go │ │ └── link_list_test.go │ ├── queue.go │ ├── skiplist │ │ ├── skip_list.go │ │ └── skip_list_test.go │ ├── sort │ │ ├── sort.go │ │ └── sort_test.go │ ├── stack.go │ ├── tree │ │ ├── tree.go │ │ └── tree_test.go │ └── util │ │ └── util.go ├── leetcode │ ├── 10.正则表达式匹配.go │ ├── 100.相同的树.go │ ├── 101.对称二叉树.go │ ├── 102.二叉树的层次遍历.go │ ├── 103.二叉树的锯齿形层次遍历.go │ ├── 104.二叉树的最大深度.go │ ├── 105.从前序与中序遍历序列构造二叉树.go │ ├── 106.从中序与后序遍历序列构造二叉树.go │ ├── 107.二叉树的层次遍历-ii.go │ ├── 108.将有序数组转换为二叉搜索树.go │ ├── 11.盛最多水的容器.go │ ├── 110.平衡二叉树.go │ ├── 111.二叉树的最小深度.go │ ├── 112.路径总和.go │ ├── 113.路径总和-ii.go │ ├── 114.二叉树展开为链表.go │ ├── 115.不同的子序列.go │ ├── 119.杨辉三角-ii.go │ ├── 121.买卖股票的最佳时机.go │ ├── 122.买卖股票的最佳时机 II.go │ ├── 124.二叉树中的最大路径和.go │ ├── 127.单词接龙.go │ ├── 129.求根到叶子节点数字之和.go │ ├── 13.roman-to-integer.go │ ├── 136.只出现一次的数字.go │ ├── 137.只出现一次的数字-ii.go │ ├── 138.复制带随机指针的链表.go │ ├── 139.单词拆分.go │ ├── 14.longest-common-prefix.go │ ├── 141.环形链表.go │ ├── 142.环形链表-ii.go │ ├── 144.二叉树的前序遍历.go │ ├── 145.二叉树的后序遍历.go │ ├── 146.lru缓存机制.go │ ├── 148.排序链表.go │ ├── 15.三数之和.go │ ├── 152.乘积最大子序列.go │ ├── 153.寻找旋转排序数组中的最小值.go │ ├── 155.最小栈.go │ ├── 16.最接近的三数之和.go │ ├── 160.相交链表.go │ ├── 162.寻找峰值.go │ ├── 167.两数之和-ii-输入有序数组.go │ ├── 169.多数元素.go │ ├── 17.电话号码的字母组合.go │ ├── 173.二叉搜索树迭代器.go │ ├── 189.旋转数组.go │ ├── 19.删除链表的倒数第n个节点.go │ ├── 198.打家劫舍.go │ ├── 199.二叉树的右视图.go │ ├── 2.两数相加.go │ ├── 20.valid-parentheses.go │ ├── 203.移除链表元素.go │ ├── 204.计数质数.go │ ├── 206.反转链表.go │ ├── 207.课程表.go │ ├── 208.实现-trie-前缀树.go │ ├── 21.merge-two-sorted-lists.go │ ├── 213.打家劫舍-ii.go │ ├── 215.数组中的第k个最大元素.go │ ├── 216.组合总和-iii.go │ ├── 217.存在重复元素.go │ ├── 219.存在重复元素-ii.go │ ├── 22.括号生成.go │ ├── 222.完全二叉树的节点个数.go │ ├── 225.用队列实现栈.go │ ├── 226.翻转二叉树.go │ ├── 227.基本计算器-ii.go │ ├── 23.合并k个排序链表.go │ ├── 230.二叉搜索树中第k小的元素.go │ ├── 232.用栈实现队列.go │ ├── 235.二叉搜索树的最近公共祖先.go │ ├── 236.二叉树的最近公共祖先.go │ ├── 237.删除链表中的节点.go │ ├── 24.两两交换链表中的节点.go │ ├── 25.k-个一组翻转链表.go │ ├── 257.二叉树的所有路径.go │ ├── 26.删除排序数组中的重复项.go │ ├── 260.只出现一次的数字-iii.go │ ├── 268.缺失数字.go │ ├── 27.移除元素.go │ ├── 28.implement-strstr.go │ ├── 287.寻找重复数.go │ ├── 29.两数相除.go │ ├── 292.nim-游戏.go │ ├── 3.无重复字符的最长子串.go │ ├── 30.串联所有单词的子串.go │ ├── 300.最长上升子序列.go │ ├── 31.下一个排列.go │ ├── 319.灯泡开关.go │ ├── 32.最长有效括号.go │ ├── 322.零钱兑换.go │ ├── 328.奇偶链表.go │ ├── 33.搜索旋转排序数组.go │ ├── 34.在排序数组中查找元素的第一个和最后一个位置.go │ ├── 349.两个数组的交集.go │ ├── 35.search-insert-position.go │ ├── 350.两个数组的交集-ii.go │ ├── 355.设计推特.go │ ├── 36.有效的数独.go │ ├── 37.解数独.go │ ├── 38.count-and-say.go │ ├── 380.常数时间插入、删除和获取随机元素.go │ ├── 381.o-1-时间插入、删除和获取随机元素-允许重复.go │ ├── 39.组合总和.go │ ├── 4.寻找两个有序数组的中位数.go │ ├── 40.组合总和-ii.go │ ├── 41.缺失的第一个正数.go │ ├── 42.接雨水.go │ ├── 43.字符串相乘.go │ ├── 432.全-o-1-的数据结构.go │ ├── 44.通配符匹配.go │ ├── 445.两数相加-ii.go │ ├── 45.跳跃游戏 II.go │ ├── 46.全排列.go │ ├── 460.lfu缓存.go │ ├── 47.全排列 II.go │ ├── 48.旋转图像.go │ ├── 49.字母异位词分组.go │ ├── 5.最长回文子串.go │ ├── 50.Pow(x, n).go │ ├── 51.N皇后.go │ ├── 52.N皇后 II.go │ ├── 53.最大子序和.go │ ├── 54.螺旋矩阵.go │ ├── 55.跳跃游戏.go │ ├── 56.合并区间.go │ ├── 57.插入区间.go │ ├── 58.最后一个单词的长度.go │ ├── 59.螺旋矩阵-ii.go │ ├── 60.第k个排列.go │ ├── 61.旋转链表.go │ ├── 62.不同路径.go │ ├── 63.不同路径-ii.go │ ├── 64.最小路径和.go │ ├── 654.最大二叉树.go │ ├── 66.加一.go │ ├── 67.二进制求和.go │ ├── 69.x 的平方根.go │ ├── 692.前k个高频单词.go │ ├── 7.reverse-integer.go │ ├── 70.爬楼梯.go │ ├── 71.简化路径.go │ ├── 725.分隔链表.go │ ├── 73.矩阵置零.go │ ├── 74.搜索二维矩阵.go │ ├── 75.颜色分类.go │ ├── 77.组合.go │ ├── 78.子集.go │ ├── 8.字符串转换整数 (atoi).go │ ├── 80.删除排序数组中的重复项-ii.go │ ├── 81.搜索旋转排序数组-ii.go │ ├── 82.删除排序链表中的重复元素-ii.go │ ├── 83.删除排序链表中的重复元素.go │ ├── 86.分隔链表.go │ ├── 88.合并两个有序数组.go │ ├── 9.palindrome-number.go │ ├── 90.子集-ii.go │ ├── 92.反转链表-ii.go │ ├── 94.二叉树的中序遍历.go │ ├── 95.不同的二叉搜索树-ii.go │ ├── 96.不同的二叉搜索树.go │ ├── 97.交错字符串.go │ ├── 98.验证二叉搜索树.go │ ├── Readme.md │ ├── a.1_shopping_cart.go │ ├── a.2_avg_age.go │ ├── a.3_string_split_count.go │ └── a.4_continue_sum.go └── main.go ├── java └── leetcode │ ├── 1.两数之和.java │ ├── 11.盛最多水的容器.java │ ├── 114.二叉树展开为链表.java │ ├── 116.填充每个节点的下一个右侧节点指针.java │ ├── 117.填充每个节点的下一个右侧节点指针-ii.java │ ├── 143.重排链表.java │ ├── 15.三数之和.java │ ├── 16.最接近的三数之和.java │ ├── 19.删除链表的倒数第n个节点.java │ ├── 2.两数相加.java │ └── 75.颜色分类.java ├── js ├── array.js ├── chain.js ├── event.js ├── framework │ ├── Angular │ │ ├── Angular数据视图双向绑定的简单实现.md │ │ ├── angular_mvvm_ver0.html │ │ └── angular_mvvm_ver1.html │ └── Vue │ │ ├── Vue简化实现.md │ │ ├── index.js │ │ ├── lib │ │ ├── Compiler.js │ │ ├── Compiler_bk.js │ │ ├── MVVM.js │ │ ├── Observer.js │ │ ├── Watcher.js │ │ └── dependence.js │ │ ├── vue_mvvm_bk1.html │ │ ├── vue_mvvm_ver0.html │ │ └── vue_mvvm_ver1.html ├── others.js ├── recursive.js ├── sort.js ├── sort.test.js ├── stack_queue.js └── tree.js ├── md ├── js中的树.md ├── js对象与哈希表.md ├── 数组与链表,堆栈与队列.md └── 递归.md └── resource ├── Array001.png ├── Chain001.jpg ├── array__003.jpg ├── hashmap__004.jpg ├── object__001.jpg └── object__002.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore file 2 | 3 | .idea 4 | .history 5 | .vscode 6 | **.o -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 qieguo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /cpp/basic/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "sort.h" 3 | 4 | int main(int argc, const char **argv) { 5 | basic::Sort s; 6 | std::vector arr = {3, 8, 9, 1, 8, 3, 4, 2}; 7 | basic::PrintVector("origin: ", arr); 8 | s.QuickSort(arr); 9 | basic::PrintVector("sorted: ", arr); 10 | } -------------------------------------------------------------------------------- /cpp/basic/sort.h: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include 3 | namespace basic { 4 | 5 | class Sort { 6 | private: 7 | void quickSortImp(std::vector &arr, int left, int right) { 8 | if (left >= right) { 9 | return; 10 | } 11 | int datum = arr[left]; 12 | int i = left, j = right; 13 | while (i < j) { // 每次循环交换两个数 14 | // 因为arr[left]已经缓存到datum,先找右侧比基准小的,直接将arr[left]换掉 15 | while (i < j && arr[j] >= datum) { 16 | j--; 17 | } 18 | arr[i] = arr[j]; 19 | while (i < j && arr[i] < datum) { 20 | i++; 21 | } 22 | arr[j] = arr[i]; 23 | } 24 | arr[i] = datum; 25 | quickSortImp(arr, left, i - 1); 26 | quickSortImp(arr, i + 1, right); 27 | } 28 | 29 | public: 30 | void QuickSort(std::vector &arr) { 31 | return quickSortImp(arr, 0, arr.size() - 1); 32 | } 33 | }; 34 | 35 | } // namespace basic -------------------------------------------------------------------------------- /cpp/basic/util.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | namespace basic { 6 | static void PrintVector(const std::string &msg, const std::vector &input) { 7 | std::cout << msg << "["; 8 | for (const auto &item : input) { 9 | std::cout << item << ","; 10 | } 11 | std::cout << "]" << std::endl; 12 | } 13 | } // namespace basic -------------------------------------------------------------------------------- /cpp/concurrent/blocking_queue.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | namespace concurrent { 8 | template class BlockingQueue { 9 | public: 10 | BlockingQueue(){}; 11 | 12 | ~BlockingQueue(){}; 13 | 14 | // block while full 15 | void push(const T &val) { 16 | std::unique_lock lock(mutex_); 17 | producer_cond_.wait(lock, [this] { return w_idx_ - r_idx_ < cap; }); 18 | data_[w_idx_ % cap] = val; 19 | w_idx_++; 20 | consumer_cond_.notify_one(); 21 | }; 22 | 23 | // block while empty 24 | T pop() { 25 | std::unique_lock lock(mutex_); 26 | consumer_cond_.wait(lock, [this] { return w_idx_ > r_idx_; }); 27 | auto idx = r_idx_ % cap; 28 | r_idx_++; 29 | producer_cond_.notify_one(); 30 | return data_[idx]; 31 | }; 32 | 33 | int size() { 34 | std::lock_guard lock(mutex_); 35 | return w_idx_ - r_idx_; 36 | } 37 | 38 | private: 39 | std::array data_; 40 | std::int64_t r_idx_ = 0; 41 | std::int64_t w_idx_ = 0; 42 | std::mutex mutex_; 43 | std::condition_variable producer_cond_; 44 | std::condition_variable consumer_cond_; 45 | }; 46 | } // namespace concurrent -------------------------------------------------------------------------------- /cpp/concurrent/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "blocking_queue.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | constexpr int num = 2; 10 | std::thread consumers[num], producers[num]; 11 | concurrent::BlockingQueue bq; 12 | for (int i = 0; i < num; ++i) { 13 | consumers[i] = std::thread([i, &bq] { 14 | int n = bq.pop(); 15 | while (n > 0) { 16 | std::printf("---- cc (%d) ---- : %d \n", i, n); 17 | n = bq.pop(); 18 | } 19 | }); 20 | producers[i] = std::thread([i, &bq] { 21 | int n = 1; 22 | while (n < 10) { 23 | std::printf("---- pp (%d) ---- : %d \n", i, i * 100 + n); 24 | bq.push(i * 100 + n); 25 | n++; 26 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 27 | } 28 | bq.push(-1); 29 | }); 30 | } 31 | 32 | // join them back: 33 | for (int i = 0; i < num; ++i) { 34 | producers[i].join(); 35 | consumers[i].join(); 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /cpp/leetcode/121.买卖股票的最佳时机.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=121 lang=cpp 3 | * 4 | * [121] 买卖股票的最佳时机 5 | * 6 | * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/description/ 7 | * 8 | * algorithms 9 | * Easy (56.84%) 10 | * Likes: 1664 11 | * Dislikes: 0 12 | * Total Accepted: 463K 13 | * Total Submissions: 814.4K 14 | * Testcase Example: '[7,1,5,3,6,4]' 15 | * 16 | * 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 17 | * 天的价格。 18 | * 19 | * 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 20 | * 卖出该股票。设计一个算法来计算你所能获取的最大利润。 21 | * 22 | * 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 23 | * 24 | * 25 | * 26 | * 示例 1: 27 | * 28 | * 29 | * 输入:[7,1,5,3,6,4] 30 | * 输出:5 31 | * 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 32 | * 6)的时候卖出,最大利润 = 6-1 = 5 。 ⁠ 注意利润不能是 7-1 = 6, 33 | * 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 34 | * 35 | * 36 | * 示例 2: 37 | * 38 | * 39 | * 输入:prices = [7,6,4,3,1] 40 | * 输出:0 41 | * 解释:在这种情况下, 没有交易完成, 所以最大利润为 0。 42 | * 43 | * 44 | * 45 | * 46 | * 提示: 47 | * 48 | * 49 | * 1 50 | * 0 51 | * 52 | * 53 | */ 54 | 55 | #include 56 | #include 57 | 58 | // @lc code=start 59 | class Solution { 60 | public: 61 | int maxProfit(std::vector &prices) { 62 | if (prices.empty()) { 63 | return 0; 64 | } 65 | int buy = prices[0]; 66 | int profit = 0; 67 | for (int i = 1; i < prices.size(); i++) { 68 | buy = std::min(buy, prices[i]); 69 | profit = std::max(profit, prices[i] - buy); 70 | } 71 | return profit; 72 | } 73 | }; 74 | // @lc code=end 75 | -------------------------------------------------------------------------------- /cpp/leetcode/128.最长连续序列.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=128 lang=cpp 3 | * 4 | * [128] 最长连续序列 5 | * 6 | * https://leetcode.cn/problems/longest-consecutive-sequence/description/ 7 | * 8 | * algorithms 9 | * Medium (54.92%) 10 | * Likes: 1645 11 | * Dislikes: 0 12 | * Total Accepted: 385.8K 13 | * Total Submissions: 703.1K 14 | * Testcase Example: '[100,4,200,1,3,2]' 15 | * 16 | * 给定一个未排序的整数数组 nums 17 | * ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 18 | * 19 | * 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 20 | * 21 | * 22 | * 23 | * 示例 1: 24 | * 25 | * 26 | * 输入:nums = [100,4,200,1,3,2] 27 | * 输出:4 28 | * 解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。 29 | * 30 | * 示例 2: 31 | * 32 | * 33 | * 输入:nums = [0,3,7,2,5,8,4,6,0,1] 34 | * 输出:9 35 | * 36 | * 37 | * 38 | * 39 | * 提示: 40 | * 41 | * 42 | * 0 43 | * -10^9 44 | * 45 | * 46 | */ 47 | #include 48 | #include 49 | 50 | using namespace std; 51 | // @lc code=start 52 | class Solution { 53 | public: 54 | // 朴素解法:遍历数组,对每一个数不断检查递增值,更新最大长度 55 | // 优化:检查递增时可以用hash set保存是否存在 56 | // 优化2:检查递增值时会有重复检查,可设法只让最小值判断一次。 57 | // 可判断-1值是否存在,如果存在则让-1去检查,直到最小值才真正循环起来判断 58 | int longestConsecutive(vector &nums) { 59 | if (nums.empty()) { 60 | return 0; 61 | } 62 | int ret = 1; 63 | set exist(nums.begin(), nums.end()); 64 | for (auto num : nums) { 65 | if (exist.find(num - 1) != exist.end()) { 66 | continue; 67 | } 68 | int cnt = 1; 69 | int cur = num + 1; 70 | while (exist.find(cur) != exist.end()) { 71 | cnt++; 72 | cur++; 73 | } 74 | ret = max(ret, cnt); 75 | } 76 | return ret; 77 | } 78 | }; 79 | // @lc code=end 80 | -------------------------------------------------------------------------------- /cpp/leetcode/136.只出现一次的数字.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=136 lang=cpp 3 | * 4 | * [136] 只出现一次的数字 5 | * 6 | * https://leetcode.cn/problems/single-number/description/ 7 | * 8 | * algorithms 9 | * Easy (72.27%) 10 | * Likes: 2760 11 | * Dislikes: 0 12 | * Total Accepted: 857.9K 13 | * Total Submissions: 1.2M 14 | * Testcase Example: '[2,2,1]' 15 | * 16 | * 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 17 | * 18 | * 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 示例 1 : 25 | * 26 | * 27 | * 输入:nums = [2,2,1] 28 | * 输出:1 29 | * 30 | * 31 | * 示例 2 : 32 | * 33 | * 34 | * 输入:nums = [4,1,2,1,2] 35 | * 输出:4 36 | * 37 | * 38 | * 示例 3 : 39 | * 40 | * 41 | * 输入:nums = [1] 42 | * 输出:1 43 | * 44 | * 45 | * 46 | * 47 | * 提示: 48 | * 49 | * 50 | * 1 <= nums.length <= 3 * 10^4 51 | * -3 * 10^4 <= nums[i] <= 3 * 10^4 52 | * 除了某个元素只出现一次以外,其余每个元素均出现两次。 53 | * 54 | * 55 | * 56 | * 57 | */ 58 | 59 | #include 60 | 61 | // @lc code=start 62 | class Solution { 63 | public: 64 | int singleNumber(std::vector& nums) { 65 | int res = 0; 66 | for (auto num: nums) { 67 | res ^= num; 68 | } 69 | return res; 70 | } 71 | }; 72 | // @lc code=end 73 | 74 | -------------------------------------------------------------------------------- /cpp/leetcode/16.最接近的三数之和.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=16 lang=cpp 3 | * 4 | * [16] 最接近的三数之和 5 | * 6 | * https://leetcode-cn.com/problems/3sum-closest/description/ 7 | * 8 | * algorithms 9 | * Medium (40.62%) 10 | * Likes: 187 11 | * Dislikes: 0 12 | * Total Accepted: 26.7K 13 | * Total Submissions: 65.8K 14 | * Testcase Example: '[-1,2,1,-4]\n1' 15 | * 16 | * 给定一个包括 n 个整数的数组 nums 和 17 | * 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 18 | * 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 19 | * 20 | * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 21 | * 22 | * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 23 | * 24 | * 25 | */ 26 | 27 | // @lc code=start 28 | #include 29 | #include 30 | #include 31 | 32 | class Solution { 33 | public: 34 | int threeSumClosest(std::vector &nums, int target) { 35 | int minDiff = INT_MAX; 36 | int closest = 0; 37 | sort(nums.begin(), nums.end()); 38 | for (int i = 0; i < nums.size(); i++) { 39 | int j = i + 1, k = nums.size() - 1; 40 | while (j < k) { 41 | int threeSum = nums[i] + nums[j] + nums[k]; 42 | int diff = abs(target - threeSum); 43 | if (diff == 0) { 44 | return 0; 45 | } 46 | if (diff < minDiff) { 47 | minDiff = diff; 48 | closest = threeSum; 49 | } 50 | if (threeSum > target) { 51 | k--; 52 | } else { 53 | j++; 54 | } 55 | } 56 | } 57 | return closest; 58 | } 59 | }; 60 | // @lc code=end 61 | 62 | int main(int argc, const char **argv) { 63 | Solution s; 64 | std::vector nums = {2,3,4,5}; 65 | auto str = s.threeSumClosest(nums, 17); 66 | std::cout << str << std::endl; 67 | return 0; 68 | } -------------------------------------------------------------------------------- /cpp/leetcode/179.最大数.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=179 lang=cpp 3 | * 4 | * [179] 最大数 5 | * 6 | * https://leetcode.cn/problems/largest-number/description/ 7 | * 8 | * algorithms 9 | * Medium (41.13%) 10 | * Likes: 1125 11 | * Dislikes: 0 12 | * Total Accepted: 197.3K 13 | * Total Submissions: 479.6K 14 | * Testcase Example: '[10,2]' 15 | * 16 | * 给定一组非负整数 17 | * nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。 18 | * 19 | * 注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。 20 | * 21 | * 22 | * 23 | * 示例 1: 24 | * 25 | * 26 | * 输入:nums = [10,2] 27 | * 输出:"210" 28 | * 29 | * 示例 2: 30 | * 31 | * 32 | * 输入:nums = [3,30,34,5,9] 33 | * 输出:"9534330" 34 | * 35 | * 36 | * 37 | * 38 | * 提示: 39 | * 40 | * 41 | * 1 <= nums.length <= 100 42 | * 0 <= nums[i] <= 10^9 43 | * 44 | * 45 | */ 46 | #include 47 | #include 48 | #include 49 | using namespace std; 50 | 51 | // @lc code=start 52 | class Solution { 53 | public: 54 | string largestNumber(vector &nums) { 55 | if (nums.empty()) { 56 | return ""; 57 | } 58 | vector arr(nums.size()); 59 | for (size_t i = 0; i < nums.size(); i++) { 60 | arr[i] = to_string(nums[i]); 61 | } 62 | sort(arr.begin(), arr.end(), [](const auto &a, const auto &b) { 63 | return a + b > b + a; // 3, 34 and 3, 32 64 | }); 65 | if (arr[0] == "0") { 66 | return "0"; 67 | } 68 | string ret; 69 | for (const auto &s : arr) { 70 | ret += s; 71 | } 72 | return ret; 73 | } 74 | }; 75 | // @lc code=end 76 | -------------------------------------------------------------------------------- /cpp/leetcode/22.括号生成.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=22 lang=cpp 3 | * 4 | * [22] 括号生成 5 | * 6 | * https://leetcode.cn/problems/generate-parentheses/description/ 7 | * 8 | * algorithms 9 | * Medium (77.56%) 10 | * Likes: 3031 11 | * Dislikes: 0 12 | * Total Accepted: 639.4K 13 | * Total Submissions: 824.2K 14 | * Testcase Example: '3' 15 | * 16 | * 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 17 | * 有效的 括号组合。 18 | * 19 | * 20 | * 21 | * 示例 1: 22 | * 23 | * 24 | * 输入:n = 3 25 | * 输出:["((()))","(()())","(())()","()(())","()()()"] 26 | * 27 | * 28 | * 示例 2: 29 | * 30 | * 31 | * 输入:n = 1 32 | * 输出:["()"] 33 | * 34 | * 35 | * 36 | * 37 | * 提示: 38 | * 39 | * 40 | * 1 <= n <= 8 41 | * 42 | * 43 | */ 44 | 45 | #include 46 | #include 47 | 48 | // @lc code=start 49 | class Solution { 50 | private: 51 | void helper(int left, int right, std::string &cur, 52 | std::vector &result) { 53 | if (left > right) { 54 | return; 55 | } 56 | if (left == 0 && right == 0) { 57 | result.push_back(cur); 58 | return; 59 | } 60 | if (left > 0) { 61 | cur.push_back('('); 62 | helper(left - 1, right, cur, result); 63 | cur.pop_back(); 64 | } 65 | if (right > 0) { 66 | cur.push_back(')'); 67 | helper(left, right - 1, cur, result); 68 | cur.pop_back(); 69 | } 70 | } 71 | 72 | public: 73 | std::vector generateParenthesis(int n) { 74 | std::vector result; 75 | std::string cur; 76 | helper(n, n, cur, result); 77 | return result; 78 | } 79 | }; 80 | // @lc code=end 81 | -------------------------------------------------------------------------------- /cpp/leetcode/279.完全平方数.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=279 lang=cpp 3 | * 4 | * [279] 完全平方数 5 | * 6 | * https://leetcode.cn/problems/perfect-squares/description/ 7 | * 8 | * algorithms 9 | * Medium (66.14%) 10 | * Likes: 1703 11 | * Dislikes: 0 12 | * Total Accepted: 403.8K 13 | * Total Submissions: 610.5K 14 | * Testcase Example: '12' 15 | * 16 | * 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 17 | * 18 | * 完全平方数 19 | * 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 20 | * 和 16 都是完全平方数,而 3 和 11 不是。 21 | * 22 | * 23 | * 24 | * 示例 1: 25 | * 26 | * 27 | * 输入:n = 12 28 | * 输出:3 29 | * 解释:12 = 4 + 4 + 4 30 | * 31 | * 示例 2: 32 | * 33 | * 34 | * 输入:n = 13 35 | * 输出:2 36 | * 解释:13 = 4 + 9 37 | * 38 | * 39 | * 提示: 40 | * 41 | * 42 | * 1 <= n <= 10^4 43 | * 44 | * 45 | */ 46 | 47 | #include 48 | #include 49 | using namespace std; 50 | 51 | // @lc code=start 52 | class Solution { 53 | public: 54 | // 完全背包问题,可选项是1~根号n内的平方数 55 | int numSquares(int n) { 56 | if (n <= 3) { 57 | return n; 58 | } 59 | vector dp(n + 1); 60 | for (int i = 1; i < n + 1; i++) { 61 | int mini = INT_MAX; 62 | for (int j = 1; j * j <= i; j++) { 63 | // dp(i)的最后一步可以是1~根号i内的所有平方数,所以步数等于min(dp[i - j * j]) + 1 64 | mini = min(mini, dp[i - j * j]); 65 | } 66 | dp[i] = mini + 1; 67 | } 68 | return dp[n]; 69 | } 70 | }; 71 | // @lc code=end 72 | -------------------------------------------------------------------------------- /cpp/leetcode/283.移动零.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=283 lang=cpp 3 | * 4 | * [283] 移动零 5 | * 6 | * https://leetcode.cn/problems/move-zeroes/description/ 7 | * 8 | * algorithms 9 | * Easy (63.80%) 10 | * Likes: 2012 11 | * Dislikes: 0 12 | * Total Accepted: 1.1M 13 | * Total Submissions: 1.7M 14 | * Testcase Example: '[0,1,0,3,12]' 15 | * 16 | * 给定一个数组 nums,编写一个函数将所有 0 17 | * 移动到数组的末尾,同时保持非零元素的相对顺序。 18 | * 19 | * 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 20 | * 21 | * 22 | * 23 | * 示例 1: 24 | * 25 | * 26 | * 输入: nums = [0,1,0,3,12] 27 | * 输出: [1,3,12,0,0] 28 | * 29 | * 30 | * 示例 2: 31 | * 32 | * 33 | * 输入: nums = [0] 34 | * 输出: [0] 35 | * 36 | * 37 | * 38 | * 提示: 39 | * 40 | * 41 | * 42 | * 1 <= nums.length <= 10^4 43 | * -2^31 <= nums[i] <= 2^31 - 1 44 | * 45 | * 46 | * 47 | * 48 | * 进阶:你能尽量减少完成的操作次数吗? 49 | * 50 | */ 51 | 52 | #include 53 | using namespace std; 54 | 55 | // @lc code=start 56 | class Solution { 57 | public: 58 | // 经典双指针 59 | void moveZeroes(vector &nums) { 60 | int n = nums.size(); 61 | if (n <= 1) { 62 | return; 63 | } 64 | int l = 0, r = 0; // l左侧全非0,lr之间全是0 65 | while (r < n) { 66 | // [0,1,0,3,12] 67 | if (nums[r] != 0) { 68 | swap(nums[l++], nums[r++]); 69 | } else { 70 | r++; 71 | } 72 | } 73 | } 74 | }; 75 | // @lc code=end 76 | -------------------------------------------------------------------------------- /cpp/leetcode/31.下一个排列.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=31 lang=cpp 3 | * 4 | * [31] 下一个排列 5 | * 6 | * https://leetcode-cn.com/problems/next-permutation/description/ 7 | * 8 | * algorithms 9 | * Medium (37.10%) 10 | * Likes: 1237 11 | * Dislikes: 0 12 | * Total Accepted: 188.9K 13 | * Total Submissions: 507.5K 14 | * Testcase Example: '[1,2,3]' 15 | * 16 | * 实现获取 下一个排列 17 | * 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 18 | * 19 | * 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 20 | * 21 | * 必须 原地 修改,只允许使用额外常数空间。 22 | * 23 | * 24 | * 25 | * 示例 1: 26 | * 27 | * 28 | * 输入:nums = [1,2,3] 29 | * 输出:[1,3,2] 30 | * 31 | * 32 | * 示例 2: 33 | * 34 | * 35 | * 输入:nums = [3,2,1] 36 | * 输出:[1,2,3] 37 | * 38 | * 39 | * 示例 3: 40 | * 41 | * 42 | * 输入:nums = [1,1,5] 43 | * 输出:[1,5,1] 44 | * 45 | * 46 | * 示例 4: 47 | * 48 | * 49 | * 输入:nums = [1] 50 | * 输出:[1] 51 | * 52 | * 53 | * 54 | * 55 | * 提示: 56 | * 57 | * 58 | * 1 59 | * 0 60 | * 61 | * 62 | */ 63 | 64 | #include 65 | #include 66 | // @lc code=start 67 | class Solution { 68 | public: 69 | void nextPermutation(std::vector &nums) { 70 | // [1,4,9,8,3,2] => [1,8,2,3,4,9] => swap48,revert9432 71 | if (nums.size() <= 1) { 72 | return; 73 | } 74 | int i = nums.size() - 2; 75 | while (i >= 0 && nums[i] >= nums[i + 1]) { 76 | i--; 77 | } 78 | if (i >= 0) { // found 79 | int j = nums.size() - 1; 80 | while (nums[j] <= nums[i]) { 81 | j--; 82 | } 83 | std::swap(nums[i], nums[j]); 84 | } 85 | std::reverse(nums.begin() + i + 1, nums.end()); 86 | } 87 | }; 88 | // @lc code=end 89 | -------------------------------------------------------------------------------- /cpp/leetcode/41.缺失的第一个正数.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=41 lang=cpp 3 | * 4 | * [41] 缺失的第一个正数 5 | * 6 | * https://leetcode-cn.com/problems/first-missing-positive/description/ 7 | * 8 | * algorithms 9 | * Hard (41.26%) 10 | * Likes: 1104 11 | * Dislikes: 0 12 | * Total Accepted: 136.6K 13 | * Total Submissions: 331.2K 14 | * Testcase Example: '[1,2,0]' 15 | * 16 | * 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。 17 | * 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 18 | * 19 | * 20 | * 21 | * 示例 1: 22 | * 23 | * 24 | * 输入:nums = [1,2,0] 25 | * 输出:3 26 | * 27 | * 28 | * 示例 2: 29 | * 30 | * 31 | * 输入:nums = [3,4,-1,1] 32 | * 输出:2 33 | * 34 | * 35 | * 示例 3: 36 | * 37 | * 38 | * 输入:nums = [7,8,9,11,12] 39 | * 输出:1 40 | * 41 | * 42 | * 43 | * 44 | * 提示: 45 | * 46 | * 47 | * 1 48 | * -2^31 49 | * 50 | * 51 | */ 52 | 53 | #include 54 | 55 | // @lc code=start 56 | class Solution { 57 | public: 58 | int firstMissingPositive(std::vector &nums) { 59 | // [3,4,0,1] => 2, -1,1,4,3 60 | for (size_t i = 0; i < nums.size(); i++) { 61 | while (nums[i] > 0 && nums[i] < nums.size() && 62 | nums[i] != nums[nums[i] - 1]) { // loop while equal 63 | std::swap(nums[i], nums[nums[i] - 1]); 64 | } 65 | } 66 | 67 | for (size_t i = 0; i < nums.size(); i++) { 68 | if (nums[i] != i + 1) { 69 | return i + 1; 70 | } 71 | } 72 | return nums.size() + 1; 73 | } 74 | }; 75 | // @lc code=end 76 | -------------------------------------------------------------------------------- /cpp/leetcode/42.接雨水.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=42 lang=cpp 3 | * 4 | * [42] 接雨水 5 | * 6 | * https://leetcode-cn.com/problems/trapping-rain-water/description/ 7 | * 8 | * algorithms 9 | * Hard (56.05%) 10 | * Likes: 2405 11 | * Dislikes: 0 12 | * Total Accepted: 257.1K 13 | * Total Submissions: 458.7K 14 | * Testcase Example: '[0,1,0,2,1,0,1,3,2,1,2,1]' 15 | * 16 | * 给定 n 个非负整数表示每个宽度为 1 17 | * 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 18 | * 19 | * 20 | * 21 | * 示例 1: 22 | * 23 | * 24 | * 25 | * 26 | * 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 27 | * 输出:6 28 | * 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 29 | * 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 30 | * 31 | * 32 | * 示例 2: 33 | * 34 | * 35 | * 输入:height = [4,2,0,3,2,5] 36 | * 输出:9 37 | * 38 | * 39 | * 40 | * 41 | * 提示: 42 | * 43 | * 44 | * n == height.length 45 | * 0 46 | * 0 47 | * 48 | * 49 | */ 50 | 51 | #include 52 | 53 | // @lc code=start 54 | class Solution { 55 | public: 56 | int trap(std::vector &height) { 57 | int left = 0, right = height.size() - 1; 58 | int leftMax = 0, rightMax = 0; 59 | int ret = 0; 60 | while (left < right) { 61 | if (height[left] < height[right]) { 62 | if (height[left] < leftMax) { 63 | ret += leftMax - height[left]; 64 | } else { 65 | leftMax = height[left]; 66 | } 67 | left++; 68 | } else { 69 | if (height[right] < rightMax) { 70 | ret += rightMax - height[right]; 71 | } else { 72 | rightMax = height[right]; 73 | } 74 | right--; 75 | } 76 | } 77 | return ret; 78 | } 79 | }; 80 | // @lc code=end 81 | -------------------------------------------------------------------------------- /cpp/leetcode/45.跳跃游戏-ii.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=45 lang=cpp 3 | * 4 | * [45] 跳跃游戏 II 5 | * 6 | * https://leetcode-cn.com/problems/jump-game-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (40.39%) 10 | * Likes: 1013 11 | * Dislikes: 0 12 | * Total Accepted: 139.1K 13 | * Total Submissions: 344.3K 14 | * Testcase Example: '[2,3,1,1,4]' 15 | * 16 | * 给定一个非负整数数组,你最初位于数组的第一个位置。 17 | * 18 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 19 | * 20 | * 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 21 | * 22 | * 假设你总是可以到达数组的最后一个位置。 23 | * 24 | * 25 | * 26 | * 示例 1: 27 | * 28 | * 29 | * 输入: [2,3,1,1,4] 30 | * 输出: 2 31 | * 解释: 跳到最后一个位置的最小跳跃数是 2。 32 | * 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 33 | * 34 | * 35 | * 示例 2: 36 | * 37 | * 38 | * 输入: [2,3,0,1,4] 39 | * 输出: 2 40 | * 41 | * 42 | * 43 | * 44 | * 提示: 45 | * 46 | * 47 | * 1 48 | * 0 49 | * 50 | * 51 | */ 52 | 53 | #include 54 | #include 55 | // 当前和下一步合并起来最大即为最优,证明: 56 | // 第1步可以走到[1,n],第2步分别可以走的最大距离是x1,x2..,根据第2步的最大距离可以选出第1步的选择 57 | // 是否存在第1步不走上面的选择但是整体最优呢?不存在,因为第2步的最大距离是覆盖了非最优解的,步数会更小。 58 | // @lc code=start 59 | class Solution { 60 | public: 61 | int jump(std::vector &nums) { 62 | if (nums.size() <= 1) { 63 | return 0; // 不用走就到末尾了 64 | } 65 | int preMax = nums[0]; // 上一步的最大位置 66 | int curMax = preMax; // 当前步的最大位置 67 | int step = 1; // 先走一步 68 | int idx = 1; 69 | while (preMax < nums.size() - 1) { // 最后不用走,算进来会多走一步 70 | // [4,1,3,2,1,2,8] 71 | curMax = std::max(curMax, idx + nums[idx]); 72 | if (idx >= preMax) { // 到了上一步的最大距离,可以确定上一步的选择 73 | preMax = curMax; 74 | step++; 75 | } 76 | idx++; 77 | } 78 | return step; 79 | } 80 | }; 81 | // @lc code=end 82 | -------------------------------------------------------------------------------- /cpp/leetcode/51.n-皇后.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=51 lang=cpp 3 | * 4 | * [51] N 皇后 5 | * 6 | * https://leetcode.cn/problems/n-queens/description/ 7 | * 8 | * algorithms 9 | * Hard (74.24%) 10 | * Likes: 1633 11 | * Dislikes: 0 12 | * Total Accepted: 278.7K 13 | * Total Submissions: 375.4K 14 | * Testcase Example: '4' 15 | * 16 | * 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 17 | * 18 | * n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 19 | * 的棋盘上,并且使皇后彼此之间不能相互攻击。 20 | * 21 | * 给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。 22 | * 23 | * 24 | * 25 | * 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 26 | * 分别代表了皇后和空位。 27 | * 28 | * 29 | * 30 | * 示例 1: 31 | * 32 | * 33 | * 输入:n = 4 34 | * 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 35 | * 解释:如上图所示,4 皇后问题存在两个不同的解法。 36 | * 37 | * 38 | * 示例 2: 39 | * 40 | * 41 | * 输入:n = 1 42 | * 输出:[["Q"]] 43 | * 44 | * 45 | * 46 | * 47 | * 提示: 48 | * 49 | * 50 | * 1 <= n <= 9 51 | * 52 | * 53 | * 54 | * 55 | */ 56 | 57 | #include 58 | #include 59 | 60 | // @lc code=start 61 | class Solution { 62 | 63 | public: 64 | std::vector> solveNQueens(int n) { 65 | 66 | } 67 | }; 68 | // @lc code=end 69 | -------------------------------------------------------------------------------- /cpp/leetcode/53.最大子数组和.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=53 lang=cpp 3 | * 4 | * [53] 最大子数组和 5 | * 6 | * https://leetcode.cn/problems/maximum-subarray/description/ 7 | * 8 | * algorithms 9 | * Medium (54.86%) 10 | * Likes: 5696 11 | * Dislikes: 0 12 | * Total Accepted: 1.3M 13 | * Total Submissions: 2.4M 14 | * Testcase Example: '[-2,1,-3,4,-1,2,1,-5,4]' 15 | * 16 | * 给你一个整数数组 nums 17 | * ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 18 | * 19 | * 子数组 是数组中的一个连续部分。 20 | * 21 | * 22 | * 23 | * 示例 1: 24 | * 25 | * 26 | * 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 27 | * 输出:6 28 | * 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 29 | * 30 | * 31 | * 示例 2: 32 | * 33 | * 34 | * 输入:nums = [1] 35 | * 输出:1 36 | * 37 | * 38 | * 示例 3: 39 | * 40 | * 41 | * 输入:nums = [5,4,-1,7,8] 42 | * 输出:23 43 | * 44 | * 45 | * 46 | * 47 | * 提示: 48 | * 49 | * 50 | * 1 <= nums.length <= 10^5 51 | * -10^4 <= nums[i] <= 10^4 52 | * 53 | * 54 | * 55 | * 56 | * 进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。 57 | * 58 | */ 59 | 60 | #include 61 | 62 | // @lc code=start 63 | class Solution { 64 | public: 65 | int maxSubArray(std::vector &nums) { 66 | if (nums.empty()) { 67 | return 0; 68 | } 69 | int ret = nums[0]; 70 | int cur = 0; 71 | for (const auto &num : nums) { 72 | cur = std::max(cur + num, num); 73 | ret = std::max(ret, cur); 74 | } 75 | return ret; 76 | } 77 | }; 78 | // @lc code=end 79 | -------------------------------------------------------------------------------- /cpp/leetcode/60.排列序列.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=60 lang=cpp 3 | * 4 | * [60] 排列序列 5 | * 6 | * https://leetcode.cn/problems/permutation-sequence/description/ 7 | * 8 | * algorithms 9 | * Hard (53.42%) 10 | * Likes: 754 11 | * Dislikes: 0 12 | * Total Accepted: 123.3K 13 | * Total Submissions: 230.8K 14 | * Testcase Example: '3\n3' 15 | * 16 | * 给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。 17 | * 18 | * 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: 19 | * 20 | * 21 | * "123" 22 | * "132" 23 | * "213" 24 | * "231" 25 | * "312" 26 | * "321" 27 | * 28 | * 29 | * 给定 n 和 k,返回第 k 个排列。 30 | * 31 | * 32 | * 33 | * 示例 1: 34 | * 35 | * 36 | * 输入:n = 3, k = 3 37 | * 输出:"213" 38 | * 39 | * 40 | * 示例 2: 41 | * 42 | * 43 | * 输入:n = 4, k = 9 44 | * 输出:"2314" 45 | * 46 | * 47 | * 示例 3: 48 | * 49 | * 50 | * 输入:n = 3, k = 1 51 | * 输出:"123" 52 | * 53 | * 54 | * 55 | * 56 | * 提示: 57 | * 58 | * 59 | * 1 60 | * 1 61 | * 62 | * 63 | */ 64 | 65 | #include 66 | #include 67 | 68 | // @lc code=start 69 | class Solution { 70 | public: 71 | std::string getPermutation(int n, int k) { 72 | std::vector factorial(n); 73 | factorial[0] = 1; 74 | for (size_t i = 1; i < n; i++) { 75 | factorial[i] = factorial[i - 1] * i; 76 | } 77 | // [1,1,2,6] 78 | std::string ret; 79 | int j; 80 | k--; // 从0开始计数 81 | std::vector nums(n); 82 | for (size_t i = 0; i < nums.size(); i++) { 83 | nums[i] = i + 1; 84 | } 85 | for (int i = n - 1; i >= 0; i--) { 86 | j = k / factorial[i]; // 2 87 | ret += (nums[j] + '0'); 88 | nums.erase(nums.begin() + j); 89 | k %= factorial[i]; 90 | } 91 | return ret; 92 | } 93 | }; 94 | // @lc code=end 95 | -------------------------------------------------------------------------------- /cpp/leetcode/62.不同路径.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=62 lang=cpp 3 | * 4 | * [62] 不同路径 5 | * 6 | * https://leetcode.cn/problems/unique-paths/description/ 7 | * 8 | * algorithms 9 | * Medium (67.72%) 10 | * Likes: 1759 11 | * Dislikes: 0 12 | * Total Accepted: 615.5K 13 | * Total Submissions: 908.8K 14 | * Testcase Example: '3\n7' 15 | * 16 | * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 17 | * 18 | * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 19 | * “Finish” )。 20 | * 21 | * 问总共有多少条不同的路径? 22 | * 23 | * 24 | * 25 | * 示例 1: 26 | * 27 | * 28 | * 输入:m = 3, n = 7 29 | * 输出:28 30 | * 31 | * 示例 2: 32 | * 33 | * 34 | * 输入:m = 3, n = 2 35 | * 输出:3 36 | * 解释: 37 | * 从左上角开始,总共有 3 条路径可以到达右下角。 38 | * 1. 向右 -> 向下 -> 向下 39 | * 2. 向下 -> 向下 -> 向右 40 | * 3. 向下 -> 向右 -> 向下 41 | * 42 | * 43 | * 示例 3: 44 | * 45 | * 46 | * 输入:m = 7, n = 3 47 | * 输出:28 48 | * 49 | * 50 | * 示例 4: 51 | * 52 | * 53 | * 输入:m = 3, n = 3 54 | * 输出:6 55 | * 56 | * 57 | * 58 | * 提示: 59 | * 60 | * 61 | * 1 62 | * 题目数据保证答案小于等于 2 * 10^9 63 | * 64 | * 65 | */ 66 | 67 | #include 68 | // @lc code=start 69 | class Solution { 70 | public: 71 | int uniquePaths(int m, int n) { 72 | if (m <= 0 || n <= 0) { 73 | return 0; 74 | } 75 | std::vector dp(n, 1); 76 | for (size_t i = 1; i < m; i++) { 77 | for (size_t j = 1; j < n; j++) { 78 | dp[j] += dp[j - 1]; 79 | } 80 | } 81 | 82 | return dp[n-1]; 83 | } 84 | }; 85 | // @lc code=end 86 | -------------------------------------------------------------------------------- /cpp/leetcode/74.搜索二维矩阵.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=74 lang=cpp 3 | * 4 | * [74] 搜索二维矩阵 5 | * 6 | * https://leetcode.cn/problems/search-a-2d-matrix/description/ 7 | * 8 | * algorithms 9 | * Medium (48.61%) 10 | * Likes: 795 11 | * Dislikes: 0 12 | * Total Accepted: 308.4K 13 | * Total Submissions: 634.3K 14 | * Testcase Example: '[[1,3,5,7],[10,11,16,20],[23,30,34,60]]\n3' 15 | * 16 | * 编写一个高效的算法来判断 m x 17 | * n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: 18 | * 19 | * 20 | * 每行中的整数从左到右按升序排列。 21 | * 每行的第一个整数大于前一行的最后一个整数。 22 | * 23 | * 24 | * 25 | * 26 | * 示例 1: 27 | * 28 | * 29 | * 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3 30 | * 输出:true 31 | * 32 | * 33 | * 示例 2: 34 | * 35 | * 36 | * 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13 37 | * 输出:false 38 | * 39 | * 40 | * 41 | * 42 | * 提示: 43 | * 44 | * 45 | * m == matrix.length 46 | * n == matrix[i].length 47 | * 1 48 | * -10^4 49 | * 50 | * 51 | */ 52 | 53 | #include 54 | #include 55 | 56 | // @lc code=start 57 | class Solution { 58 | public: 59 | bool searchMatrix(std::vector> &matrix, int target) { 60 | // 第一个大于目标值的列 61 | auto t_row = std::upper_bound( 62 | matrix.begin(), matrix.end(), target, 63 | [](const int t, const std::vector &row) { return t < row[0]; }); 64 | if (t_row == matrix.begin()) { 65 | return false; 66 | } 67 | --t_row; 68 | return std::binary_search(t_row->begin(), t_row->end(), target); 69 | } 70 | }; 71 | // @lc code=end 72 | -------------------------------------------------------------------------------- /cpp/leetcode/75.颜色分类.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=75 lang=cpp 3 | * 4 | * [75] 颜色分类 5 | * 6 | * https://leetcode-cn.com/problems/sort-colors/description/ 7 | * 8 | * algorithms 9 | * Medium (58.84%) 10 | * Likes: 954 11 | * Dislikes: 0 12 | * Total Accepted: 238.6K 13 | * Total Submissions: 403.3K 14 | * Testcase Example: '[2,0,2,1,1,0]' 15 | * 16 | * 给定一个包含红色、白色和蓝色,一共 n 17 | * 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 18 | * 19 | * 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 示例 1: 27 | * 28 | * 29 | * 输入:nums = [2,0,2,1,1,0] 30 | * 输出:[0,0,1,1,2,2] 31 | * 32 | * 33 | * 示例 2: 34 | * 35 | * 36 | * 输入:nums = [2,0,1] 37 | * 输出:[0,1,2] 38 | * 39 | * 40 | * 示例 3: 41 | * 42 | * 43 | * 输入:nums = [0] 44 | * 输出:[0] 45 | * 46 | * 47 | * 示例 4: 48 | * 49 | * 50 | * 输入:nums = [1] 51 | * 输出:[1] 52 | * 53 | * 54 | * 55 | * 56 | * 提示: 57 | * 58 | * 59 | * n == nums.length 60 | * 1 61 | * nums[i] 为 0、1 或 2 62 | * 63 | * 64 | * 65 | * 66 | * 进阶: 67 | * 68 | * 69 | * 你可以不使用代码库中的排序函数来解决这道题吗? 70 | * 你能想出一个仅使用常数空间的一趟扫描算法吗? 71 | * 72 | * 73 | */ 74 | 75 | #include 76 | 77 | // @lc code=start 78 | class Solution { 79 | public: 80 | void sortColors(std::vector &nums) { 81 | // 3指针,左之前0,中为遍历指针,右之后为2,遍历发现0跟左交换,发现2跟右交换 82 | int left = 0, cur = 0, right = nums.size() - 1; 83 | while (cur <= right) { 84 | if (nums[cur] == 0) { 85 | std::swap(nums[cur++], nums[left++]); // left不可能为2,之前已经判断过,cur可以++ 86 | } else if (nums[cur] == 2) { 87 | std::swap(nums[cur], nums[right--]); 88 | } else { 89 | cur++; 90 | } 91 | } 92 | } 93 | }; 94 | // @lc code=end 95 | -------------------------------------------------------------------------------- /cpp/leetcode/77.组合.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=77 lang=cpp 3 | * 4 | * [77] 组合 5 | * 6 | * https://leetcode-cn.com/problems/combinations/description/ 7 | * 8 | * algorithms 9 | * Medium (76.85%) 10 | * Likes: 602 11 | * Dislikes: 0 12 | * Total Accepted: 172.3K 13 | * Total Submissions: 224.2K 14 | * Testcase Example: '4\n2' 15 | * 16 | * 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 17 | * 18 | * 示例: 19 | * 20 | * 输入: n = 4, k = 2 21 | * 输出: 22 | * [ 23 | * ⁠ [2,4], 24 | * ⁠ [3,4], 25 | * ⁠ [2,3], 26 | * ⁠ [1,2], 27 | * ⁠ [1,3], 28 | * ⁠ [1,4], 29 | * ] 30 | * 31 | */ 32 | 33 | #include 34 | 35 | // @lc code=start 36 | class Solution { 37 | private: 38 | void helper(std::vector> &res, std::vector &out, int n, 39 | int k, int start) { 40 | if (k == 0) { 41 | res.emplace_back(out); 42 | return; 43 | } 44 | for (int i = start; i <= n; i++) { 45 | out.emplace_back(i); 46 | helper(res, out, n, k - 1, i + 1); 47 | out.pop_back(); 48 | } 49 | } 50 | 51 | public: 52 | std::vector> combine(int n, int k) { 53 | std::vector> res; 54 | std::vector out; 55 | helper(res, out, n, k, 1); 56 | return res; 57 | } 58 | }; 59 | // @lc code=end 60 | -------------------------------------------------------------------------------- /cpp/leetcode/78.子集.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=78 lang=cpp 3 | * 4 | * [78] 子集 5 | * 6 | * https://leetcode-cn.com/problems/subsets/description/ 7 | * 8 | * algorithms 9 | * Medium (79.88%) 10 | * Likes: 1214 11 | * Dislikes: 0 12 | * Total Accepted: 258.2K 13 | * Total Submissions: 323.2K 14 | * Testcase Example: '[1,2,3]' 15 | * 16 | * 给你一个整数数组 nums ,数组中的元素 互不相同 17 | * 。返回该数组所有可能的子集(幂集)。 18 | * 19 | * 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 20 | * 21 | * 22 | * 23 | * 示例 1: 24 | * 25 | * 26 | * 输入:nums = [1,2,3] 27 | * 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 28 | * 29 | * 30 | * 示例 2: 31 | * 32 | * 33 | * 输入:nums = [0] 34 | * 输出:[[],[0]] 35 | * 36 | * 37 | * 38 | * 39 | * 提示: 40 | * 41 | * 42 | * 1 43 | * -10 44 | * nums 中的所有元素 互不相同 45 | * 46 | * 47 | */ 48 | 49 | #include 50 | 51 | // @lc code=start 52 | class Solution { 53 | private: 54 | std::vector> subsetsAppend(std::vector &nums) { 55 | std::vector> ret; 56 | ret.push_back({}); 57 | for (auto num : nums) { 58 | int size = ret.size(); 59 | for (int i = 0; i < size; i++) { 60 | std::vector arr = ret[i]; 61 | arr.push_back(num); 62 | ret.push_back(arr); 63 | } 64 | } 65 | return ret; 66 | } 67 | 68 | public: 69 | std::vector> subsets(std::vector &nums) { 70 | return subsetsAppend(nums); 71 | } 72 | }; 73 | // @lc code=end 74 | -------------------------------------------------------------------------------- /go/basic/cache/lru_test.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestLru(t *testing.T) { 9 | cache := NewLRUCache(1) 10 | cache.Put(1, 11) 11 | cache.Put(2, 22) 12 | cache.Put(3, 33) 13 | fmt.Println("put success") 14 | 15 | v := cache.Get(2) 16 | fmt.Printf("get (2) return %v\n", v) // 返回 22 17 | 18 | v = cache.Get(2) 19 | fmt.Printf("get (2) return %v\n", v) // 返回 22 20 | 21 | cache.Put(4, 44) // 该操作会使(2,22) 作废 22 | fmt.Println("put 4 success") 23 | 24 | v = cache.Get(2) 25 | fmt.Printf("get (2) return %v \n", v) // 返回 -1 (未找到) 26 | 27 | v = cache.Get(3) 28 | fmt.Printf("get (3) return %v\n", v) // 返回 33 29 | } 30 | -------------------------------------------------------------------------------- /go/basic/concurrency/concurrency_test.go: -------------------------------------------------------------------------------- 1 | package concurrency 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func TestGlobalSingle(t *testing.T) { 12 | n := runtime.NumCPU() 13 | fmt.Println("cup num=", n) 14 | runtime.GOMAXPROCS(n) 15 | fmt.Println("start TestGlobalSingle") 16 | c := make(chan int32, 5) 17 | for i := 0; i < 20; i++ { 18 | go func() { 19 | s := GetGlobalSingle() 20 | fmt.Println("send value", s.Value) 21 | c <- s.Value 22 | fmt.Println("finish send ", s.Value) 23 | }() 24 | } 25 | 26 | /* NOTE: 如果不另外开一个goroutine来消费channel的话,程序会panic,报错是所有goroutine都休眠了 27 | 具体原因涉及到channel的for range和goroutine的调度机制。 28 | 1. for range遍历channel如何判断已经消费到了最后一个?实际上for range等同于 for{v,ok=<-c if!ok{break}} 29 | 其中ok用来标识channel是否关闭,如果没有关闭channel,那么消费的g就会一直堵塞等待消息,也就是asleep状态 30 | 2. 如果没有新开一个g,那么就是主线程一直陷入堵塞状态;如果新开了一个g的话,其实这个g就泄露了,因为他一直在等待channel的消息; 31 | 而channel中还有等待的g,那这个channel也不会被垃圾回收掉 32 | */ 33 | go func() { 34 | for v := range c { 35 | fmt.Println("receive value ", v) 36 | i++ 37 | } 38 | }() 39 | fmt.Println("end") 40 | time.Sleep(3 * time.Second) 41 | } 42 | 43 | // 新开两个子线程,分别输出1,3,5,7,9...和2,4,6,8,10...,主线程接受子线程的值,输出1,2,3,4,5... 44 | func TestAlternateOutput(t *testing.T) { 45 | n := runtime.NumCPU() 46 | fmt.Println("cpu num=", n) 47 | runtime.GOMAXPROCS(n) 48 | 49 | fmt.Println("====== start ======") 50 | fmt.Println("stage 0, go num=", runtime.NumGoroutine()) // 默认两个go 51 | 52 | // AlternateOutputViaChannel() 53 | // AlternateOutputViaAtomic() 54 | AlternateOutputViaCond() 55 | 56 | fmt.Println("====== end ======") 57 | 58 | } 59 | -------------------------------------------------------------------------------- /go/basic/concurrency/once.go: -------------------------------------------------------------------------------- 1 | package concurrency 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | // Once sync底层使用锁和原子自增实现once效果 9 | type Once struct { 10 | mu sync.Mutex 11 | count int32 12 | } 13 | 14 | // Do 提供一个do方法 15 | func (o *Once) Do(f func()) { 16 | // 使用cas限制第一次也OK? 17 | // 不ok,因为两个g同时进来的时候,其中一个没有执行f,另外一个执行了f,两个g后面取到的值是有差异的,一致性不满足 18 | // 而采用源码的方式,在抢互斥锁的时候另外一个线程堵塞,保证后续运行时都是在f执行后的状态 19 | // if atomic.CompareAndSwapInt32(&o.count, 0, 1) { 20 | // f() 21 | // } 22 | 23 | // 源码实现,先原子取数,然后再抢锁,抢到之后判断是否执行过f,若未执行则调用f,然后再原子+1 24 | if atomic.LoadInt32(&o.count) == 1 { 25 | return 26 | } 27 | o.mu.Lock() 28 | if o.count == 0 { 29 | f() 30 | atomic.StoreInt32(&o.count, 1) 31 | } 32 | o.mu.Unlock() 33 | } 34 | -------------------------------------------------------------------------------- /go/basic/concurrency/singleton.go: -------------------------------------------------------------------------------- 1 | package concurrency 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | // Singleton 单例 9 | type Singleton struct { 10 | Value int64 11 | } 12 | 13 | var s *Singleton 14 | 15 | var _ = new(sync.Once) 16 | var once = new(Once) 17 | 18 | // GetGlobalSingle 使用once来实现全局单例 19 | func GetGlobalSingle() *Singleton { 20 | once.Do(func() { 21 | s = &Singleton{ 22 | Value: time.Now().Unix(), 23 | } 24 | }) 25 | return s 26 | } 27 | -------------------------------------------------------------------------------- /go/basic/dp/dp.go: -------------------------------------------------------------------------------- 1 | package dp 2 | 3 | import ( 4 | "sort" 5 | 6 | "github.com/qieguo2016/algorithm/go/basic/util" 7 | ) 8 | 9 | /** 10 | * 求最大和子串,求给定整数数组中和最大的连续子串,输出最大和 11 | * arr: 输入整数数组,至少有一个元素 12 | */ 13 | func GetMaxSum(arr []int) int { 14 | tmp := 0 15 | maxSum := 0 16 | for i := 0; i < len(arr); i++ { 17 | tmp += arr[i] 18 | if tmp < 0 { 19 | tmp = 0 20 | } else if tmp > maxSum { 21 | maxSum = tmp 22 | } 23 | } 24 | return maxSum 25 | } 26 | 27 | // 给定金额用最少硬币数兑换 28 | // 求极值一般会考虑使用动态规划。用dp[i]表示i元的最少硬币兑换数,则状态转移方程: 29 | // dp[i]=min(dp[i-c])+1, for c in coins(遍历硬币组合) 30 | // dp[11] = min(dp[6], d[9], dp[10])+1 31 | // dp[1] = min(dp[-4], dp[-1], dp[0]) + 1 32 | // dp[0] = 0 33 | // dp[<0] invalid,用amount+1代替(硬币最小面值为1,最小有amount个,+1标识非法) 34 | // dp有两种模式,一种在迭代的时候增加记忆数组,另外一种是上来先算记忆数组 35 | // PS: 这个兑换有个特例,就是各种硬币是倍数关系的时候,这个时候退化成贪婪模式 36 | 37 | func coinChange(coins []int, amount int) int { 38 | dp := make([]int, amount+1) // dp[0]为边界,需要amount+1个 39 | for i := 0; i < amount+1; i++ { 40 | dp[i] = amount + 1 // 默认都非法 41 | } 42 | sort.Ints(coins) 43 | dp[0] = 0 44 | for i := 1; i <= amount; i++ { 45 | for j := 0; j < len(coins); j++ { 46 | if coins[j] > i { 47 | break 48 | } 49 | dp[i] = util.Min(dp[i], dp[i-coins[j]]+1) 50 | } 51 | } 52 | if dp[amount] > amount { 53 | return -1 54 | } 55 | return dp[amount] 56 | } 57 | -------------------------------------------------------------------------------- /go/basic/heap/heap_test.go: -------------------------------------------------------------------------------- 1 | package heap 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/qieguo2016/algorithm/go/basic/util" 8 | ) 9 | 10 | func printHeap(arr []int) { 11 | length := len(arr) 12 | queue := []int{0} 13 | n := 0 14 | for n < length { 15 | for _, c := range queue[n:len(queue)] { 16 | fmt.Printf("%d ", arr[c]) 17 | n++ 18 | if 2*c+1 < length { 19 | queue = append(queue, 2*c+1) 20 | } 21 | if 2*c+2 < length { 22 | queue = append(queue, 2*c+2) 23 | } 24 | } 25 | fmt.Print("\n") 26 | } 27 | } 28 | 29 | func TestSmallRootHeap(t *testing.T) { 30 | for i := 0; i < 2; i++ { 31 | arr := util.MakeRandomArray(7) 32 | fmt.Printf("origin arr=%v\n", arr) 33 | NewSmallRootHeap(arr) 34 | fmt.Printf("heap arr=%v\n", arr) 35 | printHeap(arr) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /go/basic/list/link_list_test.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func display(ll *LinkList) { 9 | var fn = func(node *LinkListNode) { 10 | fmt.Printf("%v > ", node.value) 11 | } 12 | fmt.Print("link: ") 13 | ll.Visit(fn) 14 | fmt.Print("\n") 15 | } 16 | 17 | func TestLinkList(t *testing.T) { 18 | // a := CreateLinkList() 19 | // fmt.Println("a.length", a.length) 20 | // a.Insert(1) 21 | // display(a) 22 | // a.Insert(2) 23 | // a.Insert(3) 24 | // display(a) 25 | // // display(ra) 26 | // a.InsertAfter(23, a.Find(2)) 27 | // a.InsertAfter(233, a.Find(2)) 28 | // display(a) 29 | // a.DeleteByValue(233) 30 | // display(a) 31 | // a.Delete() 32 | // display(a) 33 | // a.Delete() 34 | // display(a) 35 | 36 | // b := CreateLinkList() 37 | // b.Insert(9) 38 | // b.Insert(6) 39 | // b.Insert(5) 40 | // b.Insert(2) 41 | 42 | // c := CreateLinkList() 43 | // c.Insert(8) 44 | // c.Insert(7) 45 | // c.Insert(4) 46 | // c.Insert(1) 47 | 48 | // d := MergeSortedLinkList(b, c) 49 | // display(d) 50 | 51 | e := CreateLinkList() 52 | for index := 10; index > 0; index-- { 53 | e.Insert(index) 54 | } 55 | display(e) 56 | f := ReverseLinkList(e.head) 57 | display(&LinkList{head: f, length: 10}) 58 | ret, _ := GetRevKthFromLinkList(e.head, 0) 59 | println("ret=", ret) 60 | } 61 | -------------------------------------------------------------------------------- /go/basic/queue.go: -------------------------------------------------------------------------------- 1 | package base 2 | -------------------------------------------------------------------------------- /go/basic/skiplist/skip_list_test.go: -------------------------------------------------------------------------------- 1 | package skiplist 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestSkipList(t *testing.T) { 10 | testcase := [][]int{} 11 | testcaseStr := `[ 12 | [10,10], 13 | [9,9], 14 | [10,100], 15 | [15,15], 16 | [8,8], 17 | [3,3], 18 | [8,80], 19 | [21,21], 20 | [25,25], 21 | [32,32] 22 | ]` 23 | 24 | json.Unmarshal([]byte(testcaseStr), &testcase) 25 | 26 | s := NewSkipList() 27 | for i, data := range testcase { 28 | s.Insert(data[0], data[1]) 29 | fmt.Printf("test[%d]: skiplist insert, index=%d, data=%+v\n", i, data[0], data[1]) 30 | } 31 | fmt.Println("====== delete =======") 32 | s.Delete(9) 33 | s.Delete(21) 34 | fmt.Println("====== search =======") 35 | for i, data := range testcase { 36 | index := data[0] 37 | node := s.Search(index) 38 | fmt.Printf("test[%d]: skiplist search, index=%d, data=%+v\n", i, index, node) 39 | } 40 | fmt.Printf("skiplist rank (2, 3) = %+v\n", s.Rank(2, 3)) 41 | } 42 | -------------------------------------------------------------------------------- /go/basic/sort/sort_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func makeRandomArray(n int) []int { 10 | ret := make([]int, n) 11 | for i := 0; i < n; i++ { 12 | ret[i] = rand.Intn(n * 10) 13 | } 14 | return ret 15 | } 16 | 17 | func isArraySort(target []int) bool { 18 | if len(target) <= 1 { 19 | return true 20 | } 21 | for i := 0; i < len(target)-1; i++ { 22 | if target[i] > target[i+1] { 23 | return false 24 | } 25 | } 26 | return true 27 | } 28 | 29 | func TestQuickSort(t *testing.T) { 30 | for i := 0; i < 50; i++ { 31 | arr := makeRandomArray(10) 32 | fmt.Printf("origin arr=%v\n", arr) 33 | QuickSortInPlace(arr) 34 | isSort := isArraySort(arr) 35 | if !isSort { 36 | t.Errorf("sort fail, arr=%v\n", arr) 37 | return 38 | } 39 | fmt.Printf("sort success, arr=%v\n", arr) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /go/basic/stack.go: -------------------------------------------------------------------------------- 1 | package base 2 | -------------------------------------------------------------------------------- /go/basic/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | func Swap(arr []int, i int, j int) { 8 | tmp := arr[i] 9 | arr[i] = arr[j] 10 | arr[j] = tmp 11 | } 12 | 13 | func Min(i, j int) int { 14 | if i < j { 15 | return i 16 | } 17 | return j 18 | } 19 | 20 | func Max(i, j int) int { 21 | if i > j { 22 | return i 23 | } 24 | return j 25 | } 26 | 27 | func MakeRandomArray(n int) []int { 28 | ret := make([]int, n) 29 | for i := 0; i < n; i++ { 30 | ret[i] = rand.Intn(n * 10) 31 | } 32 | return ret 33 | } 34 | -------------------------------------------------------------------------------- /go/leetcode/100.相同的树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=100 lang=golang 3 | * 4 | * [100] 相同的树 5 | */ 6 | /** 7 | * Definition for a binary tree node. 8 | * type TreeNode struct { 9 | * Val int 10 | * Left *TreeNode 11 | * Right *TreeNode 12 | * } 13 | */ 14 | 15 | func isSameTree(p *TreeNode, q *TreeNode) bool { 16 | if p == nil || q == nil { 17 | return p == nil && q == nil 18 | } 19 | if p.Val != q.Val { 20 | return false 21 | } 22 | return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right) 23 | } 24 | 25 | -------------------------------------------------------------------------------- /go/leetcode/101.对称二叉树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=101 lang=golang 3 | * 4 | * [101] 对称二叉树 5 | */ 6 | /** 7 | * Definition for a binary tree node. 8 | * type TreeNode struct { 9 | * Val int 10 | * Left *TreeNode 11 | * Right *TreeNode 12 | * } 13 | */ 14 | 15 | func isSymmetricByNode(left *TreeNode, right *TreeNode) bool { 16 | if left == nil && right == nil { 17 | return true 18 | } 19 | if left == nil || right == nil || left.Val != right.Val { 20 | return false 21 | } 22 | return isSymmetricByNode(left.Left, right.Right) && isSymmetricByNode(left.Right, right.Left) 23 | } 24 | 25 | func isSymmetric(root *TreeNode) bool { 26 | if root == nil { 27 | return true 28 | } 29 | return isSymmetricByNode(root.Left, root.Right) 30 | } 31 | 32 | -------------------------------------------------------------------------------- /go/leetcode/102.二叉树的层次遍历.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=102 lang=golang 3 | * 4 | * [102] 二叉树的层次遍历 5 | * 6 | * https://leetcode-cn.com/problems/binary-tree-level-order-traversal/description/ 7 | * 8 | * algorithms 9 | * Medium (56.18%) 10 | * Likes: 207 11 | * Dislikes: 0 12 | * Total Accepted: 27K 13 | * Total Submissions: 48.1K 14 | * Testcase Example: '[3,9,20,null,null,15,7]' 15 | * 16 | * 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 17 | * 18 | * 例如: 19 | * 给定二叉树: [3,9,20,null,null,15,7], 20 | * 21 | * ⁠ 3 22 | * ⁠ / \ 23 | * ⁠ 9 20 24 | * ⁠ / \ 25 | * ⁠ 15 7 26 | * 27 | * 28 | * 返回其层次遍历结果: 29 | * 30 | * [ 31 | * ⁠ [3], 32 | * ⁠ [9,20], 33 | * ⁠ [15,7] 34 | * ] 35 | * 36 | * 37 | */ 38 | /** 39 | * Definition for a binary tree node. 40 | * type TreeNode struct { 41 | * Val int 42 | * Left *TreeNode 43 | * Right *TreeNode 44 | * } 45 | */ 46 | 47 | func levelOrder(root *TreeNode) [][]int { 48 | ret := [][]int{} 49 | q := []*TreeNode{} 50 | if root != nil { 51 | q = append(q, root) 52 | } 53 | i := 0 // dequeue index 54 | j := len(q) // enqueue index 55 | k := 0 56 | for i < j { 57 | // dequeue 58 | node := q[i] 59 | if k >= len(ret) { 60 | ret = append(ret, []int{}) 61 | } 62 | ret[k] = append(ret[k], node.Val) 63 | i++ 64 | // enqueue 65 | if node.Left != nil { 66 | q = append(q, node.Left) 67 | } 68 | if node.Right != nil { 69 | q = append(q, node.Right) 70 | } 71 | if i >= j { 72 | k++ // level down 73 | j = len(q) // update enqueue index 74 | } 75 | } 76 | return ret 77 | } 78 | 79 | -------------------------------------------------------------------------------- /go/leetcode/104.二叉树的最大深度.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=104 lang=golang 3 | * 4 | * [104] 二叉树的最大深度 5 | */ 6 | /** 7 | * Definition for a binary tree node. 8 | * type TreeNode struct { 9 | * Val int 10 | * Left *TreeNode 11 | * Right *TreeNode 12 | * } 13 | */ 14 | func maxDepth(root *TreeNode) int { 15 | if root == nil { 16 | return 0 17 | } 18 | if root.Left == nil && root.Right == nil { 19 | return 1 20 | } 21 | maxLeft := maxDepth(root.Left) 22 | maxRight := maxDepth(root.Right) 23 | max := maxLeft 24 | if maxRight > maxLeft { 25 | max = maxRight 26 | } 27 | return 1 + max 28 | } 29 | 30 | -------------------------------------------------------------------------------- /go/leetcode/105.从前序与中序遍历序列构造二叉树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=105 lang=golang 3 | * 4 | * [105] 从前序与中序遍历序列构造二叉树 5 | * 6 | * https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/ 7 | * 8 | * algorithms 9 | * Medium (61.23%) 10 | * Likes: 247 11 | * Dislikes: 0 12 | * Total Accepted: 24.7K 13 | * Total Submissions: 40.1K 14 | * Testcase Example: '[3,9,20,15,7]\n[9,3,15,20,7]' 15 | * 16 | * 根据一棵树的前序遍历与中序遍历构造二叉树。 17 | * 18 | * 注意: 19 | * 你可以假设树中没有重复的元素。 20 | * 21 | * 例如,给出 22 | * 23 | * 前序遍历 preorder = [3,9,20,15,7] 24 | * 中序遍历 inorder = [9,3,15,20,7] 25 | * 26 | * 返回如下的二叉树: 27 | * 28 | * ⁠ 3 29 | * ⁠ / \ 30 | * ⁠ 9 20 31 | * ⁠ / \ 32 | * ⁠ 15 7 33 | * 34 | */ 35 | /** 36 | * Definition for a binary tree node. 37 | * type TreeNode struct { 38 | * Val int 39 | * Left *TreeNode 40 | * Right *TreeNode 41 | * } 42 | */ 43 | 44 | // 前序是根左右的遍历方式,中序是左根右的遍历方式 45 | // 3是根节点,然后以根结点将中序一分为2得到左右子树,按照左右子树个数将前序也分割成两个子树 46 | // 分别递归左右子树 47 | func buildTree(preorder []int, inorder []int) *TreeNode { 48 | if len(preorder) <= 0 || len(inorder) <= 0 { 49 | return nil 50 | } 51 | mid := 0 52 | for mid < len(inorder) && inorder[mid] != preorder[0] { 53 | mid++ 54 | } 55 | ret := &TreeNode{Val: preorder[0]} 56 | ret.Left = buildTree(preorder[1:mid+1], inorder[:mid]) 57 | ret.Right = buildTree(preorder[mid+1:], inorder[mid+1:]) 58 | return ret 59 | } 60 | 61 | -------------------------------------------------------------------------------- /go/leetcode/107.二叉树的层次遍历-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=107 lang=golang 3 | * 4 | * [107] 二叉树的层次遍历 II 5 | */ 6 | /** 7 | * Definition for a binary tree node. 8 | * type TreeNode struct { 9 | * Val int 10 | * Left *TreeNode 11 | * Right *TreeNode 12 | * } 13 | */ 14 | func levelOrderBottom(root *TreeNode) [][]int { 15 | if root == nil { 16 | return [][]int{} 17 | } 18 | q := []*TreeNode{} 19 | ret := [][]int{} 20 | q = append(q, root) 21 | for len(q) > 0 { 22 | // dequeue 23 | tmp := []int{} 24 | nodes := []*TreeNode{} 25 | for _, el := range q { 26 | tmp = append(tmp, el.Val) 27 | if el.Left != nil { 28 | nodes = append(nodes, el.Left) 29 | } 30 | if el.Right != nil { 31 | nodes = append(nodes, el.Right) 32 | } 33 | } 34 | ret = append(ret, tmp) 35 | q = nodes[:] 36 | } 37 | if len(ret) <= 1 { 38 | return ret 39 | } 40 | i := len(ret) - 1 41 | rev := [][]int{} 42 | for i >= 0 { 43 | rev = append(rev, ret[i]) 44 | i-- 45 | } 46 | return rev 47 | } 48 | 49 | -------------------------------------------------------------------------------- /go/leetcode/108.将有序数组转换为二叉搜索树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=108 lang=golang 3 | * 4 | * [108] 将有序数组转换为二叉搜索树 5 | */ 6 | /** 7 | * Definition for a binary tree node. 8 | * type TreeNode struct { 9 | * Val int 10 | * Left *TreeNode 11 | * Right *TreeNode 12 | * } 13 | */ 14 | 15 | // 二叉搜索树的大小关系是 左<根<右,这个刚好就是一个中序遍历的顺序,而根是树的中点 16 | // 所以问题变成了对原数组的二分查找并按中序遍历构造树 17 | func sortedArrayToBST(nums []int) *TreeNode { 18 | if len(nums) <= 0 { 19 | return nil 20 | } 21 | if len(nums) == 1 { 22 | return &TreeNode{Val: nums[0]} 23 | } 24 | mid := len(nums) / 2 25 | node := &TreeNode{Val: nums[mid]} 26 | node.Left = sortedArrayToBST(nums[:mid]) 27 | node.Right = sortedArrayToBST(nums[mid+1:]) 28 | return node 29 | } 30 | 31 | -------------------------------------------------------------------------------- /go/leetcode/11.盛最多水的容器.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=11 lang=golang 3 | * 4 | * [11] 盛最多水的容器 5 | * 6 | * https://leetcode-cn.com/problems/container-with-most-water/description/ 7 | * 8 | * algorithms 9 | * Medium (61.94%) 10 | * Likes: 1195 11 | * Dislikes: 0 12 | * Total Accepted: 155K 13 | * Total Submissions: 250.1K 14 | * Testcase Example: '[1,8,6,2,5,4,8,3,7]' 15 | * 16 | * 给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 17 | * (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 18 | * 19 | * 说明:你不能倾斜容器,且 n 的值至少为 2。 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 26 | * 27 | * 28 | * 29 | * 示例: 30 | * 31 | * 输入:[1,8,6,2,5,4,8,3,7] 32 | * 输出:49 33 | * 34 | */ 35 | 36 | // @lc code=start 37 | // 双指针处理,取矮的一侧计算面积,且判断最大面积之后移动矮的一侧指针往前 38 | // 因为面积是由矮侧和宽度决定的,双指针可以保证宽度最大,所以矮侧与其他的搭配都不可能是最大面积 39 | func maxArea(height []int) int { 40 | // [1,8,6,2,5,4,8,3,7] 41 | max := 0 42 | li := 0 43 | ri := len(height) - 1 44 | for { 45 | if ri <= li { 46 | break 47 | } 48 | lc := height[li] 49 | rc := height[ri] 50 | w := ri - li 51 | h := 0 52 | if rc < lc { 53 | h = rc 54 | ri-- 55 | } else { 56 | h = lc 57 | li++ 58 | } 59 | area := w * h 60 | // fmt.Println(area, w, h) 61 | if area > max { 62 | max = area 63 | } 64 | 65 | } 66 | return max 67 | } 68 | // @lc code=end 69 | 70 | -------------------------------------------------------------------------------- /go/leetcode/110.平衡二叉树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=110 lang=golang 3 | * 4 | * [110] 平衡二叉树 5 | */ 6 | /** 7 | * Definition for a binary tree node. 8 | * type TreeNode struct { 9 | * Val int 10 | * Left *TreeNode 11 | * Right *TreeNode 12 | * } 13 | */ 14 | 15 | func maxDepth(root *TreeNode) int { 16 | if root == nil { 17 | return 0 18 | } 19 | maxLeft := maxDepth(root.Left) 20 | maxRight := maxDepth(root.Right) 21 | max := maxLeft 22 | if maxRight > maxLeft { 23 | max = maxRight 24 | } 25 | return 1 + max 26 | } 27 | 28 | func isBalanced(root *TreeNode) bool { 29 | if root == nil { 30 | return true 31 | } 32 | diff := maxDepth(root.Left) - maxDepth(root.Right) 33 | if diff > 1 || diff < -1 { 34 | return false 35 | } 36 | return isBalanced(root.Left) && isBalanced(root.Right) 37 | } 38 | 39 | -------------------------------------------------------------------------------- /go/leetcode/111.二叉树的最小深度.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=111 lang=golang 3 | * 4 | * [111] 二叉树的最小深度 5 | * 6 | * https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/description/ 7 | * 8 | * algorithms 9 | * Easy (39.15%) 10 | * Likes: 131 11 | * Dislikes: 0 12 | * Total Accepted: 21.3K 13 | * Total Submissions: 54.4K 14 | * Testcase Example: '[3,9,20,null,null,15,7]' 15 | * 16 | * 给定一个二叉树,找出其最小深度。 17 | * 18 | * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 19 | * 20 | * 说明: 叶子节点是指没有子节点的节点。 21 | * 22 | * 示例: 23 | * 24 | * 给定二叉树 [3,9,20,null,null,15,7], 25 | * 26 | * ⁠ 3 27 | * ⁠ / \ 28 | * ⁠ 9 20 29 | * ⁠ / \ 30 | * ⁠ 15 7 31 | * 32 | * 返回它的最小深度  2. 33 | * 34 | */ 35 | /** 36 | * Definition for a binary tree node. 37 | * type TreeNode struct { 38 | * Val int 39 | * Left *TreeNode 40 | * Right *TreeNode 41 | * } 42 | */ 43 | 44 | func minDepth(root *TreeNode) int { 45 | if root == nil { 46 | return 0 47 | } 48 | if root.Left == nil { 49 | return 1+minDepth(root.Right) 50 | } 51 | if root.Right == nil { 52 | return 1+minDepth(root.Left) 53 | } 54 | i := minDepth(root.Left) + 1 55 | j := minDepth(root.Right) + 1 56 | if i4->11->2。 33 | * 34 | */ 35 | /** 36 | * Definition for a binary tree node. 37 | * type TreeNode struct { 38 | * Val int 39 | * Left *TreeNode 40 | * Right *TreeNode 41 | * } 42 | */ 43 | func hasPathSum(root *TreeNode, sum int) bool { 44 | if root == nil { 45 | return false 46 | } 47 | rest := sum - root.Val 48 | if root.Left != nil && hasPathSum(root.Left, rest) { 49 | return true 50 | } 51 | if root.Right != nil && hasPathSum(root.Right, rest) { 52 | return true 53 | } 54 | return root.Left == nil && root.Right == nil && rest == 0 55 | } 56 | 57 | -------------------------------------------------------------------------------- /go/leetcode/113.路径总和-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=113 lang=golang 3 | * 4 | * [113] 路径总和 II 5 | * 6 | * https://leetcode-cn.com/problems/path-sum-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (55.11%) 10 | * Likes: 88 11 | * Dislikes: 0 12 | * Total Accepted: 9.5K 13 | * Total Submissions: 17.2K 14 | * Testcase Example: '[5,4,8,11,null,13,4,7,2,null,null,5,1]\n22' 15 | * 16 | * 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 17 | * 18 | * 说明: 叶子节点是指没有子节点的节点。 19 | * 20 | * 示例: 21 | * 给定如下二叉树,以及目标和 sum = 22, 22 | * 23 | * ⁠ 5 24 | * ⁠ / \ 25 | * ⁠ 4 8 26 | * ⁠ / / \ 27 | * ⁠ 11 13 4 28 | * ⁠ / \ / \ 29 | * ⁠ 7 2 5 1 30 | * 31 | * 32 | * 返回: 33 | * 34 | * [ 35 | * ⁠ [5,4,11,2], 36 | * ⁠ [5,8,4,5] 37 | * ] 38 | * 39 | * 40 | */ 41 | /** 42 | * Definition for a binary tree node. 43 | * type TreeNode struct { 44 | * Val int 45 | * Left *TreeNode 46 | * Right *TreeNode 47 | * } 48 | */ 49 | 50 | func pathSum(root *TreeNode, sum int) [][]int { 51 | s := &solution{ 52 | ret: [][]int{}, 53 | path: []int{}, 54 | } 55 | s.helper(root, sum) 56 | return s.ret 57 | } 58 | 59 | type solution struct { 60 | ret [][]int 61 | path []int 62 | } 63 | 64 | func (s *solution) helper(root *TreeNode, sum int) { 65 | if root == nil { 66 | return 67 | } 68 | rest := sum - root.Val 69 | s.path = append(s.path, root.Val) 70 | defer func() { 71 | s.path = s.path[0 : len(s.path)-1] 72 | }() 73 | if root.Left == nil && root.Right == nil && rest == 0 { 74 | s.ret = append(s.ret, append([]int{}, s.path...)) 75 | return 76 | } 77 | s.helper(root.Left, rest) 78 | s.helper(root.Right, rest) 79 | } 80 | -------------------------------------------------------------------------------- /go/leetcode/114.二叉树展开为链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=114 lang=golang 3 | * 4 | * [114] 二叉树展开为链表 5 | * 6 | * https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/description/ 7 | * 8 | * algorithms 9 | * Medium (69.55%) 10 | * Likes: 424 11 | * Dislikes: 0 12 | * Total Accepted: 51.6K 13 | * Total Submissions: 74.2K 14 | * Testcase Example: '[1,2,5,3,4,null,6]' 15 | * 16 | * 给定一个二叉树,原地将它展开为一个单链表。 17 | * 18 | * 19 | * 20 | * 例如,给定二叉树 21 | * 22 | * ⁠ 1 23 | * ⁠ / \ 24 | * ⁠ 2 5 25 | * ⁠/ \ \ 26 | * 3 4 6 27 | * 28 | * 将其展开为: 29 | * 30 | * 1 31 | * ⁠\ 32 | * ⁠ 2 33 | * ⁠ \ 34 | * ⁠ 3 35 | * ⁠ \ 36 | * ⁠ 4 37 | * ⁠ \ 38 | * ⁠ 5 39 | * ⁠ \ 40 | * ⁠ 6 41 | * 42 | */ 43 | 44 | // @lc code=start 45 | /** 46 | * Definition for a binary tree node. 47 | * type TreeNode struct { 48 | * Val int 49 | * Left *TreeNode 50 | * Right *TreeNode 51 | * } 52 | */ 53 | 54 | // 递归处理即可 55 | func flatten(root *TreeNode) { 56 | if root == nil { 57 | return 58 | } 59 | flatten(root.Left) 60 | flatten(root.Right) 61 | tmp := root.Right 62 | root.Right = root.Left 63 | root.Left = nil 64 | for root.Right != nil { 65 | root = root.Right 66 | } 67 | root.Right = tmp 68 | } 69 | // @lc code=end 70 | 71 | -------------------------------------------------------------------------------- /go/leetcode/119.杨辉三角-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=119 lang=golang 3 | * 4 | * [119] 杨辉三角 II 5 | * 6 | * https://leetcode-cn.com/problems/pascals-triangle-ii/description/ 7 | * 8 | * algorithms 9 | * Easy (65.40%) 10 | * Likes: 293 11 | * Dislikes: 0 12 | * Total Accepted: 118.3K 13 | * Total Submissions: 180.9K 14 | * Testcase Example: '3' 15 | * 16 | * 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。 17 | * 18 | * 19 | * 20 | * 在杨辉三角中,每个数是它左上方和右上方的数的和。 21 | * 22 | * 示例: 23 | * 24 | * 输入: 3 25 | * 输出: [1,3,3,1] 26 | * 27 | * 28 | * 进阶: 29 | * 30 | * 你可以优化你的算法到 O(k) 空间复杂度吗? 31 | * 32 | */ 33 | 34 | // @lc code=start 35 | func getRow(rowIndex int) []int { 36 | // 1 37 | // 1 1 38 | // 1 2 1 39 | // 1 3 3 1 40 | // 1 4 6 4 1 41 | // var pre, cur []int 42 | // for i := 0; i <= rowIndex; i++ { // 每次构造一行数据 43 | // cur = make([]int, i+1) 44 | // cur[0], cur[i] = 1, 1 45 | // for j := 1; j < i; j++ { 46 | // cur[j] = pre[j-1] + pre[j] 47 | // } 48 | // pre = cur 49 | // } 50 | 51 | // 优化空间,由cur[j] = pre[j-1] + pre[j]可知每次只和上一次结果有关 52 | // 这里如果使用递归的模式,就可以去掉pre数组 53 | // 每个数字是由它左肩上的数字加和得到,而递推是等于行内相加,所以不可以递推 54 | row := make([]int, rowIndex+1) 55 | row[0] = 1 56 | for i := 1; i <= rowIndex; i++ { 57 | for j := i; j > 0; j-- { 58 | row[j] += row[j-1] 59 | } 60 | } 61 | return row 62 | } 63 | 64 | // @lc code=end 65 | 66 | -------------------------------------------------------------------------------- /go/leetcode/121.买卖股票的最佳时机.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=121 lang=golang 3 | * 4 | * [121] 买卖股票的最佳时机 5 | * 6 | * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/description/ 7 | * 8 | * algorithms 9 | * Easy (50.14%) 10 | * Likes: 442 11 | * Dislikes: 0 12 | * Total Accepted: 54.1K 13 | * Total Submissions: 107.8K 14 | * Testcase Example: '[7,1,5,3,6,4]' 15 | * 16 | * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 17 | * 18 | * 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 19 | * 20 | * 注意你不能在买入股票前卖出股票。 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: [7,1,5,3,6,4] 25 | * 输出: 5 26 | * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 27 | * ⁠ 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 28 | * 29 | * 30 | * 示例 2: 31 | * 32 | * 输入: [7,6,4,3,1] 33 | * 输出: 0 34 | * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 35 | * 36 | * 37 | */ 38 | 39 | // 假设买点在第一天,后面发现如果有更低的,就更新买点。 40 | // 在发现更低买点的时候,是不可能在这个时候卖出的,所以最大利润是昨天的利润 41 | // 遍历下来,不断更新买点和比较最大利润,就可以得到结果 42 | func maxProfit(prices []int) int { 43 | if len(prices) <= 1 { 44 | return 0 45 | } 46 | buy := prices[0] 47 | res := 0 48 | for i := 1; i < len(prices); i++ { 49 | if prices[i] < buy { 50 | buy = prices[i] 51 | } 52 | tmp := prices[i] - buy 53 | if tmp > res { 54 | res = tmp 55 | } 56 | } 57 | return res 58 | } 59 | 60 | -------------------------------------------------------------------------------- /go/leetcode/122.买卖股票的最佳时机 II.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=122 lang=golang 3 | * 4 | * [122] 买卖股票的最佳时机 II 5 | * 6 | * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ 7 | * 8 | * algorithms 9 | * Easy (55.32%) 10 | * Likes: 483 11 | * Dislikes: 0 12 | * Total Accepted: 80.9K 13 | * Total Submissions: 145.8K 14 | * Testcase Example: '[7,1,5,3,6,4]' 15 | * 16 | * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 17 | * 18 | * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 19 | * 20 | * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: [7,1,5,3,6,4] 25 | * 输出: 7 26 | * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 27 | * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 28 | * 29 | * 30 | * 示例 2: 31 | * 32 | * 输入: [1,2,3,4,5] 33 | * 输出: 4 34 | * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 35 | * 。 36 | * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 37 | * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 38 | * 39 | * 40 | * 示例 3: 41 | * 42 | * 输入: [7,6,4,3,1] 43 | * 输出: 0 44 | * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 45 | * 46 | */ 47 | func maxProfit(prices []int) int { 48 | if len(prices) < 2 { 49 | return 0 50 | } 51 | res := 0 52 | for i := 1; i < len(prices); i++ { 53 | if j := prices[i] - prices[i-1]; j > 0 { 54 | res += j 55 | } 56 | } 57 | return res 58 | } 59 | 60 | -------------------------------------------------------------------------------- /go/leetcode/129.求根到叶子节点数字之和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=129 lang=golang 3 | * 4 | * [129] 求根到叶子节点数字之和 5 | * 6 | * https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/description/ 7 | * 8 | * algorithms 9 | * Medium (59.92%) 10 | * Likes: 92 11 | * Dislikes: 0 12 | * Total Accepted: 13.4K 13 | * Total Submissions: 22.3K 14 | * Testcase Example: '[1,2,3]' 15 | * 16 | * 给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 17 | * 18 | * 例如,从根到叶子节点路径 1->2->3 代表数字 123。 19 | * 20 | * 计算从根到叶子节点生成的所有数字之和。 21 | * 22 | * 说明: 叶子节点是指没有子节点的节点。 23 | * 24 | * 示例 1: 25 | * 26 | * 输入: [1,2,3] 27 | * ⁠ 1 28 | * ⁠ / \ 29 | * ⁠ 2 3 30 | * 输出: 25 31 | * 解释: 32 | * 从根到叶子节点路径 1->2 代表数字 12. 33 | * 从根到叶子节点路径 1->3 代表数字 13. 34 | * 因此,数字总和 = 12 + 13 = 25. 35 | * 36 | * 示例 2: 37 | * 38 | * 输入: [4,9,0,5,1] 39 | * ⁠ 4 40 | * ⁠ / \ 41 | * ⁠ 9 0 42 | * / \ 43 | * 5 1 44 | * 输出: 1026 45 | * 解释: 46 | * 从根到叶子节点路径 4->9->5 代表数字 495. 47 | * 从根到叶子节点路径 4->9->1 代表数字 491. 48 | * 从根到叶子节点路径 4->0 代表数字 40. 49 | * 因此,数字总和 = 495 + 491 + 40 = 1026. 50 | * 51 | */ 52 | 53 | // package leetcode 54 | 55 | // @lc code=start 56 | /** 57 | * Definition for a binary tree node. 58 | * type TreeNode struct { 59 | * Val int 60 | * Left *TreeNode 61 | * Right *TreeNode 62 | * } 63 | */ 64 | func sumNumbers(root *TreeNode) int { 65 | return dfs(root, 0) 66 | } 67 | 68 | func dfs(root *TreeNode, parent int) int { 69 | if root == nil { 70 | return 0 71 | } 72 | if root.Left == nil && root.Right == nil { 73 | return root.Val + parent 74 | } 75 | parent = 10 * (parent + root.Val) // 40 | 490 76 | return dfs(root.Left, parent) + dfs(root.Right, parent) 77 | } 78 | 79 | // @lc code=end 80 | -------------------------------------------------------------------------------- /go/leetcode/136.只出现一次的数字.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=136 lang=golang 3 | * 4 | * [136] 只出现一次的数字 5 | * 6 | * https://leetcode-cn.com/problems/single-number/description/ 7 | * 8 | * algorithms 9 | * Easy (63.24%) 10 | * Likes: 924 11 | * Dislikes: 0 12 | * Total Accepted: 121.3K 13 | * Total Submissions: 188.9K 14 | * Testcase Example: '[2,2,1]' 15 | * 16 | * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 17 | * 18 | * 说明: 19 | * 20 | * 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: [2,2,1] 25 | * 输出: 1 26 | * 27 | * 28 | * 示例 2: 29 | * 30 | * 输入: [4,1,2,1,2] 31 | * 输出: 4 32 | * 33 | */ 34 | 35 | // @lc code=start 36 | // 异或:相同的位置置0,不同的位置1 37 | // 因此,对数组所有元素进行异或,出现2次的数字的所有位被抵消了,只剩出现1次的数字 38 | func singleNumber(nums []int) int { 39 | ret := nums[0] 40 | for i := 1; i < len(nums); i++ { 41 | ret ^= nums[i] 42 | } 43 | return ret 44 | } 45 | // @lc code=end 46 | 47 | -------------------------------------------------------------------------------- /go/leetcode/137.只出现一次的数字-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=137 lang=golang 3 | * 4 | * [137] 只出现一次的数字 II 5 | * 6 | * https://leetcode-cn.com/problems/single-number-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (64.83%) 10 | * Likes: 210 11 | * Dislikes: 0 12 | * Total Accepted: 15.8K 13 | * Total Submissions: 24.4K 14 | * Testcase Example: '[2,2,3,2]' 15 | * 16 | * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。 17 | * 18 | * 说明: 19 | * 20 | * 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: [2,2,3,2] 25 | * 输出: 3 26 | * 27 | * 28 | * 示例 2: 29 | * 30 | * 输入: [0,1,0,1,0,1,99] 31 | * 输出: 99 32 | * 33 | */ 34 | 35 | // @lc code=start 36 | func singleNumber(nums []int) int { 37 | ret := 0 38 | // 遍历32个位,分别统计每个位上1的个数,除掉特殊的那个数字,其他数字都出现了3次,所以个数必然是3的倍数 39 | // 只要将个数模3,就可以得到特殊数在这个位上是否为1了 40 | for i := 0; i < 64; i++ { // 注意64位机器上int就是64位,如果写的32则在64位机器会失败 41 | sum := 0 42 | for _, num := range nums { 43 | sum += (num >> i) & 1 // 第i位是否为1 44 | } 45 | ret |= (sum % 3) << i // sum%3是目标数在该位的值 46 | } 47 | return ret 48 | } 49 | // @lc code=end 50 | 51 | -------------------------------------------------------------------------------- /go/leetcode/139.单词拆分.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=139 lang=golang 3 | * 4 | * [139] 单词拆分 5 | * 6 | * https://leetcode-cn.com/problems/word-break/description/ 7 | * 8 | * algorithms 9 | * Medium (42.78%) 10 | * Likes: 204 11 | * Dislikes: 0 12 | * Total Accepted: 20.1K 13 | * Total Submissions: 47K 14 | * Testcase Example: '"leetcode"\n["leet","code"]' 15 | * 16 | * 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 17 | * 18 | * 说明: 19 | * 20 | * 21 | * 拆分时可以重复使用字典中的单词。 22 | * 你可以假设字典中没有重复的单词。 23 | * 24 | * 25 | * 示例 1: 26 | * 27 | * 输入: s = "leetcode", wordDict = ["leet", "code"] 28 | * 输出: true 29 | * 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。 30 | * 31 | * 32 | * 示例 2: 33 | * 34 | * 输入: s = "applepenapple", wordDict = ["apple", "pen"] 35 | * 输出: true 36 | * 解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。 37 | * 注意你可以重复使用字典中的单词。 38 | * 39 | * 40 | * 示例 3: 41 | * 42 | * 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 43 | * 输出: false 44 | * 45 | * 46 | */ 47 | // package leetcode 48 | 49 | // 开始理解错误,以为只要包含字典里面的单词就行,其实是要拆成字典里面的组合,不能有别的单词 50 | // @lc code=start 51 | func wordBreak(s string, wordDict []string) bool { 52 | wordMap := map[string]bool{} 53 | for _, word := range wordDict { 54 | wordMap[word] = true 55 | } 56 | dp := make([]bool, len(s)+1) 57 | dp[0] = true 58 | for i := 1; i <= len(s); i++ { 59 | for j := 0; j < i; j++ { 60 | // dp[j]是j之前都可以拆分,再加上j:i这段也可以被拆分,那就可以被拆分了 61 | if dp[j] && wordMap[s[j:i]] { 62 | dp[i] = true 63 | break 64 | } 65 | } 66 | } 67 | return dp[len(s)] 68 | } 69 | 70 | // @lc code=end 71 | -------------------------------------------------------------------------------- /go/leetcode/14.longest-common-prefix.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=14 lang=golang 3 | * 4 | * [14] 最长公共前缀 5 | * 6 | * https://leetcode-cn.com/problems/longest-common-prefix/description/ 7 | * 8 | * algorithms 9 | * Easy (31.45%) 10 | * Total Accepted: 47.4K 11 | * Total Submissions: 150.5K 12 | * Testcase Example: '["flower","flow","flight"]' 13 | * 14 | * 编写一个函数来查找字符串数组中的最长公共前缀。 15 | * 16 | * 如果不存在公共前缀,返回空字符串 ""。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: ["flower","flow","flight"] 21 | * 输出: "fl" 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: ["dog","racecar","car"] 27 | * 输出: "" 28 | * 解释: 输入不存在公共前缀。 29 | * 30 | * 31 | * 说明: 32 | * 33 | * 所有输入只包含小写字母 a-z 。 34 | * 35 | */ 36 | func longestCommonPrefix(strs []string) string { 37 | ret := []byte{} 38 | i := 0 39 | if len(strs) == 0 { 40 | return "" 41 | } 42 | for { 43 | var c byte 44 | for _, str := range strs { 45 | if i > len(str)-1 { 46 | return string(ret) 47 | } 48 | if c == 0 { 49 | c = str[i] 50 | continue 51 | } 52 | if c != str[i] { 53 | return string(ret) 54 | } 55 | } 56 | ret = append(ret, c) 57 | i++ 58 | } 59 | return "" 60 | } 61 | -------------------------------------------------------------------------------- /go/leetcode/141.环形链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=141 lang=golang 3 | * 4 | * [141] 环形链表 5 | * 6 | * https://leetcode-cn.com/problems/linked-list-cycle/description/ 7 | * 8 | * algorithms 9 | * Easy (39.61%) 10 | * Likes: 288 11 | * Dislikes: 0 12 | * Total Accepted: 42.1K 13 | * Total Submissions: 106.4K 14 | * Testcase Example: '[3,2,0,-4]\n1' 15 | * 16 | * 给定一个链表,判断链表中是否有环。 17 | * 18 | * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 19 | * 20 | * 21 | * 22 | * 示例 1: 23 | * 24 | * 输入:head = [3,2,0,-4], pos = 1 25 | * 输出:true 26 | * 解释:链表中有一个环,其尾部连接到第二个节点。 27 | * 28 | * 29 | * 30 | * 31 | * 示例 2: 32 | * 33 | * 输入:head = [1,2], pos = 0 34 | * 输出:true 35 | * 解释:链表中有一个环,其尾部连接到第一个节点。 36 | * 37 | * 38 | * 39 | * 40 | * 示例 3: 41 | * 42 | * 输入:head = [1], pos = -1 43 | * 输出:false 44 | * 解释:链表中没有环。 45 | * 46 | * 47 | * 48 | * 49 | * 50 | * 51 | * 进阶: 52 | * 53 | * 你能用 O(1)(即,常量)内存解决此问题吗? 54 | * 55 | */ 56 | /** 57 | * Definition for singly-linked list. 58 | * type ListNode struct { 59 | * Val int 60 | * Next *ListNode 61 | * } 62 | */ 63 | func hasCycle(head *ListNode) bool { 64 | slow := head 65 | fast := head 66 | for fast != nil && fast.Next != nil { 67 | slow = slow.Next 68 | fast = fast.Next.Next 69 | if slow == fast { 70 | return true 71 | } 72 | } 73 | return false 74 | } 75 | 76 | -------------------------------------------------------------------------------- /go/leetcode/142.环形链表-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=142 lang=golang 3 | * 4 | * [142] 环形链表 II 5 | * 6 | * https://leetcode-cn.com/problems/linked-list-cycle-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (39.49%) 10 | * Likes: 168 11 | * Dislikes: 0 12 | * Total Accepted: 16.9K 13 | * Total Submissions: 42.7K 14 | * Testcase Example: '[3,2,0,-4]\n1' 15 | * 16 | * 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 17 | * 18 | * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 19 | * 20 | * 说明:不允许修改给定的链表。 21 | * 22 | * 23 | * 24 | * 示例 1: 25 | * 26 | * 输入:head = [3,2,0,-4], pos = 1 27 | * 输出:tail connects to node index 1 28 | * 解释:链表中有一个环,其尾部连接到第二个节点。 29 | * 30 | * 31 | * 32 | * 33 | * 示例 2: 34 | * 35 | * 输入:head = [1,2], pos = 0 36 | * 输出:tail connects to node index 0 37 | * 解释:链表中有一个环,其尾部连接到第一个节点。 38 | * 39 | * 40 | * 41 | * 42 | * 示例 3: 43 | * 44 | * 输入:head = [1], pos = -1 45 | * 输出:no cycle 46 | * 解释:链表中没有环。 47 | * 48 | * 49 | * 50 | * 51 | * 52 | * 53 | * 进阶: 54 | * 你是否可以不用额外空间解决此题? 55 | * 56 | */ 57 | /** 58 | * Definition for singly-linked list. 59 | * type ListNode struct { 60 | * Val int 61 | * Next *ListNode 62 | * } 63 | */ 64 | func detectCycle(head *ListNode) *ListNode { 65 | slow := head 66 | fast := head 67 | for fast != nil && fast.Next != nil { 68 | slow = slow.Next 69 | fast = fast.Next.Next 70 | if slow == fast { 71 | break 72 | } 73 | } 74 | if fast == nil || fast.Next == nil { 75 | return nil 76 | } 77 | slow = head 78 | fast = fast 79 | for slow != fast { 80 | slow = slow.Next 81 | fast = fast.Next 82 | } 83 | return fast 84 | } 85 | 86 | -------------------------------------------------------------------------------- /go/leetcode/148.排序链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=148 lang=golang 3 | * 4 | * [148] 排序链表 5 | * 6 | * https://leetcode-cn.com/problems/sort-list/description/ 7 | * 8 | * algorithms 9 | * Medium (60.39%) 10 | * Likes: 194 11 | * Dislikes: 0 12 | * Total Accepted: 13.4K 13 | * Total Submissions: 22.3K 14 | * Testcase Example: '[4,2,1,3]' 15 | * 16 | * 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: 4->2->1->3 21 | * 输出: 1->2->3->4 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: -1->5->3->4->0 27 | * 输出: -1->0->3->4->5 28 | * 29 | */ 30 | /** 31 | * Definition for singly-linked list. 32 | * type ListNode struct { 33 | * Val int 34 | * Next *ListNode 35 | * } 36 | */ 37 | 38 | // 采用非原地快排 39 | func sortList(head *ListNode) *ListNode { 40 | if head == nil || head.Next == nil { 41 | return head 42 | } 43 | sl := &ListNode{} 44 | ll := &ListNode{} 45 | sn := sl // 小端当前节点 46 | ln := ll // 大端当前节点 47 | // 单次比较,比较基准取头节点 48 | cur := head.Next // 注意基准要单独出来,否则不能满足一个元素的退出条件 49 | for cur != nil { 50 | if cur.Val < head.Val { 51 | sn.Next = cur 52 | sn = cur 53 | } else { 54 | ln.Next = cur 55 | ln = cur 56 | } 57 | cur = cur.Next 58 | } 59 | // 切断原链表 60 | sn.Next = nil 61 | ln.Next = nil 62 | // 递归快排 63 | sl = sortList(sl.Next) 64 | ll = sortList(ll.Next) 65 | // 合并返回新队列 66 | cur = sl 67 | if cur != nil { 68 | for cur.Next != nil { 69 | cur = cur.Next 70 | } 71 | cur.Next = head 72 | head.Next = nil // 注意要切断原head 73 | if ll != nil { 74 | head.Next = ll 75 | } 76 | return sl 77 | } 78 | head.Next = ll 79 | return head 80 | } 81 | -------------------------------------------------------------------------------- /go/leetcode/15.三数之和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=15 lang=golang 3 | * 4 | * [15] 三数之和 5 | * 6 | * https://leetcode-cn.com/problems/3sum/description/ 7 | * 8 | * algorithms 9 | * Medium (22.51%) 10 | * Likes: 1015 11 | * Dislikes: 0 12 | * Total Accepted: 58.1K 13 | * Total Submissions: 258.1K 14 | * Testcase Example: '[-1,0,1,2,-1,-4]' 15 | * 16 | * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 17 | * ?找出所有满足条件且不重复的三元组。 18 | * 19 | * 注意:答案中不可以包含重复的三元组。 20 | * 21 | * 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 22 | * 23 | * 满足要求的三元组集合为: 24 | * [ 25 | * ⁠ [-1, 0, 1], 26 | * ⁠ [-1, -1, 2] 27 | * ] 28 | * 29 | * 30 | */ 31 | 32 | import ( 33 | "sort" 34 | ) 35 | 36 | // 1. 先排序 37 | // 2. 固定一个,后两个数从边缘往中间搜索 38 | // 3. 做一些减枝优化 39 | func threeSum(nums []int) [][]int { 40 | sort.Ints(nums) 41 | ret := [][]int{} 42 | // 三元组,所以只需要遍历到倒数第三个 43 | for i := 0; i < len(nums) - 2; i++ { 44 | // 剪枝优化1,最小值>0则退出 45 | if nums[i] > 0 { 46 | break 47 | } 48 | // 去重1,与前面相同则不再搜索 49 | if i > 0 && nums[i] == nums[i-1] { 50 | continue 51 | } 52 | // 缓存target 53 | target := 0 - nums[i] 54 | // 双指针分别指向两侧边缘 55 | j, k := i+1, len(nums)-1 56 | for j < k { 57 | if nums[j] + nums[k] == target { 58 | ret = append(ret, []int{nums[i], nums[j], nums[k]}) 59 | // 去重2 60 | for j < k && nums[j] == nums[j + 1] { 61 | j++ 62 | } 63 | // 去重3 64 | for j < k && nums[k] == nums[k - 1] { 65 | k-- 66 | } 67 | j++ 68 | k-- 69 | } else if nums[j] + nums[k] < target { 70 | j++ 71 | } else { 72 | k-- 73 | } 74 | } 75 | } 76 | return ret 77 | } 78 | 79 | -------------------------------------------------------------------------------- /go/leetcode/152.乘积最大子序列.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=152 lang=golang 3 | * 4 | * [152] 乘积最大子序列 5 | * 6 | * https://leetcode-cn.com/problems/maximum-product-subarray/description/ 7 | * 8 | * algorithms 9 | * Medium (35.91%) 10 | * Likes: 308 11 | * Dislikes: 0 12 | * Total Accepted: 26.1K 13 | * Total Submissions: 72.4K 14 | * Testcase Example: '[2,3,-2,4]' 15 | * 16 | * 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: [2,3,-2,4] 21 | * 输出: 6 22 | * 解释: 子数组 [2,3] 有最大乘积 6。 23 | * 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: [-2,0,-1] 28 | * 输出: 0 29 | * 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 30 | * 31 | */ 32 | 33 | // package leetcode 34 | 35 | // 跟53.最大子序和有点类似,但是乘法中会有负数存在,而且负负可以得正 36 | // 所以可以用max和min分别记录正向和负向的最大值,每次判断一下当前数的正负区别对待 37 | // @lc code=start 38 | 39 | func max(a, b int) int { 40 | if a > b { 41 | return a 42 | } 43 | return b 44 | } 45 | 46 | func min(a, b int) int { 47 | if a < b { 48 | return a 49 | } 50 | return b 51 | } 52 | 53 | func maxProduct(nums []int) int { 54 | if len(nums) <= 0 { 55 | return 0 56 | } 57 | res := nums[0] 58 | maximum, minimum := res, res 59 | for i := 1; i < len(nums); i++ { 60 | cur := nums[i] 61 | if cur > 0 { 62 | minimum = min(minimum*cur, cur) 63 | maximum = max(maximum*cur, cur) 64 | } else { 65 | tmp := minimum 66 | minimum = min(maximum*cur, cur) 67 | maximum = max(tmp*cur, cur) 68 | } 69 | res = max(res, maximum) 70 | } 71 | return res 72 | } 73 | 74 | // @lc code=end 75 | -------------------------------------------------------------------------------- /go/leetcode/153.寻找旋转排序数组中的最小值.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=153 lang=golang 3 | * 4 | * [153] 寻找旋转排序数组中的最小值 5 | * 6 | * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/description/ 7 | * 8 | * algorithms 9 | * Medium (52.20%) 10 | * Likes: 331 11 | * Dislikes: 0 12 | * Total Accepted: 99.1K 13 | * Total Submissions: 189.7K 14 | * Testcase Example: '[3,4,5,1,2]' 15 | * 16 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。 17 | * 18 | * 请找出其中最小的元素。 19 | * 20 | * 21 | * 22 | * 示例 1: 23 | * 24 | * 25 | * 输入:nums = [3,4,5,1,2] 26 | * 输出:1 27 | * 28 | * 29 | * 示例 2: 30 | * 31 | * 32 | * 输入:nums = [4,5,6,7,0,1,2] 33 | * 输出:0 34 | * 35 | * 36 | * 示例 3: 37 | * 38 | * 39 | * 输入:nums = [1] 40 | * 输出:1 41 | * 42 | * 43 | * 44 | * 45 | * 提示: 46 | * 47 | * 48 | * 1 49 | * -5000 50 | * nums 中的所有整数都是 唯一 的 51 | * nums 原来是一个升序排序的数组,但在预先未知的某个点上进行了旋转 52 | * 53 | * 54 | */ 55 | 56 | // @lc code=start 57 | // [3,4,5,1,2],递归比较左中右3个数,当不符合向右递增时,表示转折点在这个区间内。 58 | func findMin(nums []int) int { 59 | left := 0 60 | right := len(nums) - 1 61 | for left < right { 62 | mid := left + (right-left)/2 63 | if nums[mid] > nums[right] { 64 | left = mid+1 65 | } else { 66 | right = mid 67 | } 68 | } 69 | 70 | return nums[left] 71 | } 72 | // @lc code=end 73 | 74 | -------------------------------------------------------------------------------- /go/leetcode/16.最接近的三数之和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=16 lang=golang 3 | * 4 | * [16] 最接近的三数之和 5 | * 6 | * https://leetcode-cn.com/problems/3sum-closest/description/ 7 | * 8 | * algorithms 9 | * Medium (40.62%) 10 | * Likes: 187 11 | * Dislikes: 0 12 | * Total Accepted: 26.7K 13 | * Total Submissions: 65.8K 14 | * Testcase Example: '[-1,2,1,-4]\n1' 15 | * 16 | * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 17 | * 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 18 | * 19 | * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 20 | * 21 | * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 22 | * 23 | * 24 | */ 25 | 26 | import ( 27 | "sort" 28 | "math" 29 | ) 30 | 31 | func threeSumClosest(nums []int, target int) int { 32 | // 默认有解:数组长度为3以上 33 | minDiff := math.MaxFloat64 34 | closest := 0 35 | sort.Ints(nums) 36 | println(nums) 37 | l := len(nums) 38 | for i := 0; i < l - 2; i++ { 39 | j, k := i+1, l-1 40 | for j < k { 41 | threeSum := nums[i] + nums[j] + nums[k] 42 | diff := math.Abs(float64(target - threeSum)) 43 | if diff < minDiff { 44 | closest = threeSum 45 | minDiff = diff 46 | } 47 | if target == threeSum { 48 | break // 0最接近 49 | } 50 | if target > threeSum { 51 | j++ 52 | } else { 53 | k-- 54 | } 55 | } 56 | } 57 | return closest 58 | } 59 | 60 | -------------------------------------------------------------------------------- /go/leetcode/162.寻找峰值.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=162 lang=golang 3 | * 4 | * [162] 寻找峰值 5 | * 6 | * https://leetcode-cn.com/problems/find-peak-element/description/ 7 | * 8 | * algorithms 9 | * Medium (47.80%) 10 | * Likes: 327 11 | * Dislikes: 0 12 | * Total Accepted: 65.5K 13 | * Total Submissions: 136.7K 14 | * Testcase Example: '[1,2,3,1]' 15 | * 16 | * 峰值元素是指其值大于左右相邻值的元素。 17 | * 18 | * 给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。 19 | * 20 | * 数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。 21 | * 22 | * 你可以假设 nums[-1] = nums[n] = -∞。 23 | * 24 | * 示例 1: 25 | * 26 | * 输入: nums = [1,2,3,1] 27 | * 输出: 2 28 | * 解释: 3 是峰值元素,你的函数应该返回其索引 2。 29 | * 30 | * 示例 2: 31 | * 32 | * 输入: nums = [1,2,1,3,5,6,4] 33 | * 输出: 1 或 5 34 | * 解释: 你的函数可以返回索引 1,其峰值元素为 2; 35 | * 或者返回索引 5, 其峰值元素为 6。 36 | * 37 | * 38 | * 说明: 39 | * 40 | * 你的解法应该是 O(logN) 时间复杂度的。 41 | * 42 | */ 43 | 44 | // @lc code=start 45 | // 好好利用左右边界都是负无穷这个条件,二分查找 46 | // 向上趋势则右侧必有峰值,向下趋势则左侧必有峰值 47 | func findPeakElement(nums []int) int { 48 | return findHelper(nums, 0, len(nums)-1) 49 | } 50 | 51 | func findHelper(nums []int, l, r int) int { 52 | if l == r { 53 | return l 54 | } 55 | mid := l + (r - l) / 2 56 | if nums[mid]>nums[mid+1] { 57 | return findHelper(nums, l, mid) 58 | } 59 | return findHelper(nums, mid+1, r) 60 | } 61 | // @lc code=end 62 | 63 | -------------------------------------------------------------------------------- /go/leetcode/167.两数之和-ii-输入有序数组.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=167 lang=golang 3 | * 4 | * [167] 两数之和 II - 输入有序数组 5 | * 6 | * https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/description/ 7 | * 8 | * algorithms 9 | * Easy (48.65%) 10 | * Likes: 135 11 | * Dislikes: 0 12 | * Total Accepted: 26K 13 | * Total Submissions: 53.3K 14 | * Testcase Example: '[2,7,11,15]\n9' 15 | * 16 | * 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 17 | * 18 | * 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 19 | * 20 | * 说明: 21 | * 22 | * 23 | * 返回的下标值(index1 和 index2)不是从零开始的。 24 | * 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 25 | * 26 | * 27 | * 示例: 28 | * 29 | * 输入: numbers = [2, 7, 11, 15], target = 9 30 | * 输出: [1,2] 31 | * 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 32 | * 33 | */ 34 | 35 | // 双指针解法,头尾各一个指针,分别向中间遍历 36 | // package leetcode 37 | 38 | // @lc code=start 39 | func twoSum(numbers []int, target int) []int { 40 | length := len(numbers) 41 | if length < 2 { 42 | return []int{} 43 | } 44 | left, right := 0, length-1 45 | for left < right { 46 | tmp := numbers[left] + numbers[right] 47 | if tmp == target { 48 | return []int{left + 1, right + 1} 49 | } 50 | if tmp > target { 51 | right-- 52 | } else { 53 | left++ 54 | } 55 | } 56 | return []int{} 57 | } 58 | 59 | // @lc code=end 60 | -------------------------------------------------------------------------------- /go/leetcode/169.多数元素.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=169 lang=golang 3 | * 4 | * [169] 多数元素 5 | * 6 | * https://leetcode-cn.com/problems/majority-element/description/ 7 | * 8 | * algorithms 9 | * Easy (64.84%) 10 | * Likes: 778 11 | * Dislikes: 0 12 | * Total Accepted: 228.4K 13 | * Total Submissions: 352.3K 14 | * Testcase Example: '[3,2,3]' 15 | * 16 | * 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 17 | * 18 | * 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 19 | * 20 | * 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: [3,2,3] 25 | * 输出: 3 26 | * 27 | * 示例 2: 28 | * 29 | * 输入: [2,2,1,1,1,2,2] 30 | * 输出: 2 31 | * 32 | * 33 | */ 34 | 35 | // @lc code=start 36 | // hash记录 37 | func majorityElement(nums []int) int { 38 | m := map[int]int{} 39 | ret := 0 40 | max := 0 41 | for _, n := range nums { 42 | v, ok := m[n]; 43 | if ok { 44 | v = v+1 45 | } else { 46 | v = 1 47 | } 48 | m[n] = v 49 | if v > max { 50 | max = v 51 | ret = n 52 | } 53 | } 54 | return ret 55 | } 56 | // @lc code=end 57 | 58 | -------------------------------------------------------------------------------- /go/leetcode/17.电话号码的字母组合.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=17 lang=golang 3 | * 4 | * [17] 电话号码的字母组合 5 | * 6 | * https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/description/ 7 | * 8 | * algorithms 9 | * Medium (49.81%) 10 | * Likes: 361 11 | * Dislikes: 0 12 | * Total Accepted: 29.9K 13 | * Total Submissions: 60.1K 14 | * Testcase Example: '"23"' 15 | * 16 | * 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 17 | * 18 | * 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 19 | * 20 | * 21 | * 22 | * 示例: 23 | * 24 | * 输入:"23" 25 | * 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 26 | * 27 | * 28 | * 说明: 29 | * 尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。 30 | * 31 | */ 32 | 33 | // @lc code=start 34 | var mm = [][]string{ 35 | []string{"a","b", "c"}, // 2 36 | []string{"d", "e", "f"}, 37 | []string{"g", "h", "i"}, 38 | []string{"j", "k", "l"}, 39 | []string{"m", "n", "o"}, 40 | []string{"p", "q", "r", "s"}, 41 | []string{"t", "u", "v"}, 42 | []string{"w", "x", "y", "z"}, // 9 43 | } 44 | const two rune = '2' 45 | 46 | func dfs(cs *[]rune, level int, out string, res *[]string) { 47 | if level >= len(*cs) { 48 | *res = append(*res, out) // 复制值 49 | return 50 | } 51 | i := int((*cs)[level]-two) 52 | if i < 0 || i >= len(mm) { 53 | return 54 | } 55 | str := mm[i] 56 | for _, s := range str { 57 | dfs(cs, level+1, out+s, res) 58 | } 59 | } 60 | 61 | func letterCombinations(digits string) []string { 62 | ret := []string{} 63 | n := len(digits) 64 | if n <= 0 { 65 | return ret 66 | } 67 | cs := []rune(digits) 68 | dfs(&cs, 0, "", &ret) 69 | return ret 70 | } 71 | // @lc code=end 72 | 73 | -------------------------------------------------------------------------------- /go/leetcode/19.删除链表的倒数第n个节点.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=19 lang=golang 3 | * 4 | * [19] 删除链表的倒数第N个节点 5 | */ 6 | /** 7 | * Definition for singly-linked list. 8 | * type ListNode struct { 9 | * Val int 10 | * Next *ListNode 11 | * } 12 | */ 13 | 14 | // n从1开始,仅有一个元素移除返回nil 15 | func removeNthFromEnd(head *ListNode, n int) *ListNode { 16 | if head == nil || n < 0 { 17 | return head 18 | } 19 | dummy := &ListNode{Next: head} 20 | k := 0 21 | left := dummy 22 | right := dummy 23 | for right.Next != nil && k < n { 24 | right = right.Next 25 | k++ 26 | } 27 | if k < n { // n超过链表长度 28 | return dummy.Next 29 | } 30 | for right.Next != nil { 31 | right = right.Next 32 | left = left.Next 33 | } 34 | node := left.Next 35 | if node != nil { 36 | left.Next = node.Next 37 | node.Next = nil 38 | } 39 | return dummy.Next 40 | } 41 | 42 | -------------------------------------------------------------------------------- /go/leetcode/199.二叉树的右视图.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=199 lang=golang 3 | * 4 | * [199] 二叉树的右视图 5 | * 6 | * https://leetcode-cn.com/problems/binary-tree-right-side-view/description/ 7 | * 8 | * algorithms 9 | * Medium (64.85%) 10 | * Likes: 478 11 | * Dislikes: 0 12 | * Total Accepted: 112.5K 13 | * Total Submissions: 173.4K 14 | * Testcase Example: '[1,2,3,null,5,null,4]' 15 | * 16 | * 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 17 | * 18 | * 示例: 19 | * 20 | * 输入: [1,2,3,null,5,null,4] 21 | * 输出: [1, 3, 4] 22 | * 解释: 23 | * 24 | * ⁠ 1 <--- 25 | * ⁠/ \ 26 | * 2 3 <--- 27 | * ⁠\ \ 28 | * ⁠ 5 4 <--- 29 | * 30 | * 31 | */ 32 | 33 | // @lc code=start 34 | /** 35 | * Definition for a binary tree node. 36 | * type TreeNode struct { 37 | * Val int 38 | * Left *TreeNode 39 | * Right *TreeNode 40 | * } 41 | */ 42 | 43 | // 层次遍历,每层取最后一个节点即可。 44 | func rightSideView(root *TreeNode) []int { 45 | if root == nil { 46 | return []int{} 47 | } 48 | ret := []int{} 49 | queue := []*TreeNode{root} 50 | for len(queue) > 0 { 51 | level := []*TreeNode{} 52 | var last int 53 | for _, node := range queue { 54 | last = node.Val 55 | if node.Left != nil { 56 | level = append(level, node.Left) 57 | } 58 | if node.Right != nil { 59 | level = append(level, node.Right) 60 | } 61 | } 62 | ret = append(ret, last) 63 | queue = level 64 | } 65 | return ret 66 | } 67 | 68 | // @lc code=end 69 | 70 | -------------------------------------------------------------------------------- /go/leetcode/2.两数相加.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=2 lang=golang 3 | * 4 | * [2] 两数相加 5 | * 6 | * https://leetcode-cn.com/problems/add-two-numbers/description/ 7 | * 8 | * algorithms 9 | * Medium (32.49%) 10 | * Total Accepted: 85.6K 11 | * Total Submissions: 262.6K 12 | * Testcase Example: '[2,4,3]\n[5,6,4]' 13 | * 14 | * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 15 | * 16 | * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 17 | * 18 | * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 19 | * 20 | * 示例: 21 | * 22 | * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 23 | * 输出:7 -> 0 -> 8 24 | * 原因:342 + 465 = 807 25 | * 26 | * 27 | */ 28 | /** 29 | * Definition for singly-linked list. 30 | * type ListNode struct { 31 | * Val int 32 | * Next *ListNode 33 | * } 34 | */ 35 | func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { 36 | dummy := &ListNode{} 37 | c := dummy 38 | n := 0 // 进位数 39 | for l1 != nil || l2 != nil { 40 | s := n 41 | if l1 != nil { 42 | s += l1.Val 43 | l1 = l1.Next 44 | } 45 | if l2 != nil { 46 | s += l2.Val 47 | l2 = l2.Next 48 | } 49 | n = s / 10 50 | c.Next = &ListNode{Val: s % 10} 51 | c = c.Next 52 | } 53 | if n != 0 { 54 | c.Next = &ListNode{Val: n} 55 | } 56 | return dummy.Next 57 | } 58 | 59 | -------------------------------------------------------------------------------- /go/leetcode/20.valid-parentheses.go: -------------------------------------------------------------------------------- 1 | import "fmt" 2 | 3 | /* 4 | * @lc app=leetcode.cn id=20 lang=golang 5 | * 6 | * [20] 有效的括号 7 | * 8 | * https://leetcode-cn.com/problems/valid-parentheses/description/ 9 | * 10 | * algorithms 11 | * Easy (36.00%) 12 | * Total Accepted: 42.9K 13 | * Total Submissions: 118.9K 14 | * Testcase Example: '"()"' 15 | * 16 | * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 17 | * 18 | * 有效字符串需满足: 19 | * 20 | * 21 | * 左括号必须用相同类型的右括号闭合。 22 | * 左括号必须以正确的顺序闭合。 23 | * 24 | * 25 | * 注意空字符串可被认为是有效字符串。 26 | * 27 | * 示例 1: 28 | * 29 | * 输入: "()" 30 | * 输出: true 31 | * 32 | * 33 | * 示例 2: 34 | * 35 | * 输入: "()[]{}" 36 | * 输出: true 37 | * 38 | * 39 | * 示例 3: 40 | * 41 | * 输入: "(]" 42 | * 输出: false 43 | * 44 | * 45 | * 示例 4: 46 | * 47 | * 输入: "([)]" 48 | * 输出: false 49 | * 50 | * 51 | * 示例 5: 52 | * 53 | * 输入: "{[]}" 54 | * 输出: true 55 | * 56 | */ 57 | func isValid(s string) bool { 58 | if s == "" { 59 | return true 60 | } 61 | // '(',')','{','}','[',']' 62 | left := map[string]string{ 63 | "(": ")", 64 | "{": "}", 65 | "[": "]", 66 | } 67 | right := map[string]string{ 68 | ")": "(", 69 | "}": "{", 70 | "]": "[", 71 | } 72 | stack := []string{} 73 | for _, cr := range s { 74 | c := fmt.Sprintf("%c", cr) 75 | if _, exist := left[c]; exist { 76 | stack = append(stack, c) 77 | continue 78 | } 79 | w, exist := right[c] 80 | si := len(stack) - 1 81 | if !exist || si < 0 || w != stack[si] { 82 | return false 83 | } 84 | stack = stack[:si] 85 | } 86 | return len(stack) == 0 87 | } 88 | -------------------------------------------------------------------------------- /go/leetcode/203.移除链表元素.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=203 lang=golang 3 | * 4 | * [203] 移除链表元素 5 | * 6 | * https://leetcode-cn.com/problems/remove-linked-list-elements/description/ 7 | * 8 | * algorithms 9 | * Easy (41.18%) 10 | * Likes: 238 11 | * Dislikes: 0 12 | * Total Accepted: 25.9K 13 | * Total Submissions: 62.8K 14 | * Testcase Example: '[1,2,6,3,4,5,6]\n6' 15 | * 16 | * 删除链表中等于给定值 val 的所有节点。 17 | * 18 | * 示例: 19 | * 20 | * 输入: 1->2->6->3->4->5->6, val = 6 21 | * 输出: 1->2->3->4->5 22 | * 23 | * 24 | */ 25 | /** 26 | * Definition for singly-linked list. 27 | * type ListNode struct { 28 | * Val int 29 | * Next *ListNode 30 | * } 31 | */ 32 | func removeElements(head *ListNode, val int) *ListNode { 33 | dummy := &ListNode{} 34 | dummy.Next = head 35 | pre := dummy 36 | for pre != nil && pre.Next != nil { 37 | if pre.Next.Val == val { 38 | tmp := pre.Next 39 | pre.Next = tmp.Next 40 | tmp.Next = nil 41 | } else { 42 | pre = pre.Next 43 | } 44 | } 45 | return dummy.Next 46 | } 47 | 48 | -------------------------------------------------------------------------------- /go/leetcode/204.计数质数.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=204 lang=golang 3 | * 4 | * [204] 计数质数 5 | * 6 | * https://leetcode-cn.com/problems/count-primes/description/ 7 | * 8 | * algorithms 9 | * Easy (38.19%) 10 | * Likes: 702 11 | * Dislikes: 0 12 | * Total Accepted: 150.5K 13 | * Total Submissions: 394.1K 14 | * Testcase Example: '10' 15 | * 16 | * 统计所有小于非负整数 n 的质数的数量。 17 | * 18 | * 19 | * 20 | * 示例 1: 21 | * 22 | * 输入:n = 10 23 | * 输出:4 24 | * 解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 25 | * 26 | * 27 | * 示例 2: 28 | * 29 | * 输入:n = 0 30 | * 输出:0 31 | * 32 | * 33 | * 示例 3: 34 | * 35 | * 输入:n = 1 36 | * 输出:0 37 | * 38 | * 39 | * 40 | * 41 | * 提示: 42 | * 43 | * 44 | * 0 <= n <= 5 * 10^6 45 | * 46 | * 47 | */ 48 | 49 | // @lc code=start 50 | func countPrimes(n int) int { 51 | // 1. 对于每一个数,从2开始到根号n试探是否能被整除,到根号n是因为大于根号n之后,另外一个因子也必然小于根号n 52 | // 2. 假如一个数是质数,那2x,3x就不再是质数,可以递推一直标记到n 53 | // 3. 2中的标记会有重复,比如24,2、3、4、6、8、12都会算一次,可以用线性筛优化,具体不展开 54 | composite := make([]bool, n) 55 | count := 0 56 | for i := 2; i < n; i++ { 57 | if !composite[i] { 58 | count++ 59 | for j := i + i; j < n; j += i { 60 | composite[j] = true 61 | } 62 | } 63 | } 64 | return count 65 | } 66 | 67 | // @lc code=end 68 | 69 | -------------------------------------------------------------------------------- /go/leetcode/206.反转链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=206 lang=golang 3 | * 4 | * [206] 反转链表 5 | */ 6 | /** 7 | * Definition for singly-linked list. 8 | * type ListNode struct { 9 | * Val int 10 | * Next *ListNode 11 | * } 12 | */ 13 | 14 | // func reverseList(head *ListNode) *ListNode { 15 | // dummy := &ListNode{} 16 | // dummy.Next = head 17 | // for head != nil && head.Next != nil { 18 | // n := head.Next 19 | // head.Next = head.Next.Next 20 | // n.Next = dummy.Next 21 | // dummy.Next = n 22 | // } 23 | // return dummy.Next 24 | // } 25 | 26 | // 递归实现,借助函数调用栈实现 27 | func reverseList(head *ListNode) *ListNode { 28 | if head == nil || head.Next == nil { 29 | return head 30 | } 31 | last := reverseList(head.Next) // 用递归找到最后一个 32 | head.Next.Next = head // 4>3 3>2 33 | head.Next = nil // 3>nil 2>nil 34 | return last 35 | } 36 | -------------------------------------------------------------------------------- /go/leetcode/21.merge-two-sorted-lists.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=21 lang=golang 3 | * 4 | * [21] 合并两个有序链表 5 | * 6 | * https://leetcode-cn.com/problems/merge-two-sorted-lists/description/ 7 | * 8 | * algorithms 9 | * Easy (51.82%) 10 | * Total Accepted: 40.7K 11 | * Total Submissions: 78.3K 12 | * Testcase Example: '[1,2,4]\n[1,3,4]' 13 | * 14 | * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 15 | * 16 | * 示例: 17 | * 18 | * 输入:1->2->4, 1->3->4 19 | * 输出:1->1->2->3->4->4 20 | * 21 | * 22 | */ 23 | /** 24 | * Definition for singly-linked list. 25 | * type ListNode struct { 26 | * Val int 27 | * Next *ListNode 28 | * } 29 | */ 30 | func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { 31 | if l1 == nil { 32 | return l2 33 | } 34 | if l2 == nil { 35 | return l1 36 | } 37 | cn := &ListNode{} 38 | ret := &ListNode{Next: cn} // 预加一个链表头,方便遍历 39 | for { 40 | // 其中一条链表已经遍历完,直接将另外一条非空链接上去 41 | if l1 == nil || l2 == nil { 42 | if l1 != nil { 43 | cn.Val = l1.Val 44 | cn.Next = l1.Next 45 | } 46 | if l2 != nil { 47 | cn.Val = l2.Val 48 | cn.Next = l2.Next 49 | } 50 | break 51 | } 52 | 53 | var v int 54 | if l1.Val < l2.Val { 55 | v = l1.Val 56 | l1 = l1.Next 57 | } else { 58 | v = l2.Val 59 | l2 = l2.Next 60 | } 61 | 62 | cn.Val = v 63 | cn.Next = &ListNode{} 64 | cn = cn.Next 65 | } 66 | return ret.Next // 去掉预加的链表头 67 | } 68 | -------------------------------------------------------------------------------- /go/leetcode/213.打家劫舍-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=213 lang=golang 3 | * 4 | * [213] 打家劫舍 II 5 | * 6 | * https://leetcode-cn.com/problems/house-robber-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (35.22%) 10 | * Likes: 146 11 | * Dislikes: 0 12 | * Total Accepted: 14.8K 13 | * Total Submissions: 41.8K 14 | * Testcase Example: '[2,3,2]' 15 | * 16 | * 17 | * 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 18 | * 19 | * 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 20 | * 21 | * 示例 1: 22 | * 23 | * 输入: [2,3,2] 24 | * 输出: 3 25 | * 解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。 26 | * 27 | * 28 | * 示例 2: 29 | * 30 | * 输入: [1,2,3,1] 31 | * 输出: 4 32 | * 解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 33 | * 偷窃到的最高金额 = 1 + 3 = 4 。 34 | * 35 | */ 36 | 37 | // package leetcode 38 | // 思路跟198一样,关键是将环换成普通队列形式,那么可以将头尾去掉,然后再比较头尾 39 | // 可以分成[0, n-1]和[1, n]两种组合,分别覆盖了头和尾部,取两者大值即可 40 | 41 | // @lc code=start 42 | 43 | func max(a, b int) int { 44 | if a > b { 45 | return a 46 | } 47 | return b 48 | } 49 | 50 | func rob(nums []int) int { 51 | if len(nums) <= 0 { 52 | return 0 53 | } 54 | if len(nums) <= 1 { 55 | return nums[0] 56 | } 57 | return max(helper(nums, 0, len(nums)-1), helper(nums, 1, len(nums))) 58 | } 59 | 60 | func helper(nums []int, left int, right int) int { 61 | even, odd := 0, 0 62 | for i := left; i < right; i++ { 63 | cur := nums[i] 64 | if i%2 == 0 { 65 | even = max(even+cur, odd) 66 | } else { 67 | odd = max(odd+cur, even) 68 | } 69 | } 70 | return max(even, odd) 71 | } 72 | 73 | // @lc code=end 74 | -------------------------------------------------------------------------------- /go/leetcode/216.组合总和-iii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=216 lang=golang 3 | * 4 | * [216] 组合总和 III 5 | * 6 | * https://leetcode-cn.com/problems/combination-sum-iii/description/ 7 | * 8 | * algorithms 9 | * Medium (69.01%) 10 | * Likes: 71 11 | * Dislikes: 0 12 | * Total Accepted: 10.2K 13 | * Total Submissions: 14.8K 14 | * Testcase Example: '3\n7' 15 | * 16 | * 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。 17 | * 18 | * 说明: 19 | * 20 | * 21 | * 所有数字都是正整数。 22 | * 解集不能包含重复的组合。  23 | * 24 | * 25 | * 示例 1: 26 | * 27 | * 输入: k = 3, n = 7 28 | * 输出: [[1,2,4]] 29 | * 30 | * 31 | * 示例 2: 32 | * 33 | * 输入: k = 3, n = 9 34 | * 输出: [[1,2,6], [1,3,5], [2,3,4]] 35 | * 36 | * 37 | */ 38 | 39 | // @lc code=start 40 | func combinationSum3(k int, n int) [][]int { 41 | out := []int{} 42 | res := [][]int{} 43 | dfs(k, n, 1, 10, &out, &res) 44 | return res 45 | } 46 | 47 | func dfs(k int, n int, start int, end int, out *[]int, res *[][]int) { 48 | if k == 0 && n == 0 { 49 | *res = append(*res, append([]int{}, (*out)...)) 50 | return 51 | } 52 | if k < 0 || n < 0 { 53 | return 54 | } 55 | for i := start; i < end; i++ { 56 | *out = append(*out, i) 57 | dfs(k-1, n-i, i+1, end, out, res) 58 | *out = (*out)[:len(*out)-1] 59 | } 60 | } 61 | // @lc code=end 62 | 63 | -------------------------------------------------------------------------------- /go/leetcode/217.存在重复元素.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=217 lang=golang 3 | * 4 | * [217] 存在重复元素 5 | * 6 | * https://leetcode-cn.com/problems/contains-duplicate/description/ 7 | * 8 | * algorithms 9 | * Easy (48.33%) 10 | * Likes: 142 11 | * Dislikes: 0 12 | * Total Accepted: 59K 13 | * Total Submissions: 121.9K 14 | * Testcase Example: '[1,2,3,1]' 15 | * 16 | * 给定一个整数数组,判断是否存在重复元素。 17 | * 18 | * 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 19 | * 20 | * 示例 1: 21 | * 22 | * 输入: [1,2,3,1] 23 | * 输出: true 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: [1,2,3,4] 28 | * 输出: false 29 | * 30 | * 示例 3: 31 | * 32 | * 输入: [1,1,1,3,3,4,3,2,4,2] 33 | * 输出: true 34 | * 35 | */ 36 | func containsDuplicate(nums []int) bool { 37 | m := map[int]bool{} 38 | for _, n := range nums { 39 | if _, ok := m[n]; ok { 40 | return true 41 | } 42 | m[n] = true 43 | } 44 | return false 45 | } 46 | 47 | -------------------------------------------------------------------------------- /go/leetcode/219.存在重复元素-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=219 lang=golang 3 | * 4 | * [219] 存在重复元素 II 5 | * 6 | * https://leetcode-cn.com/problems/contains-duplicate-ii/description/ 7 | * 8 | * algorithms 9 | * Easy (34.49%) 10 | * Likes: 87 11 | * Dislikes: 0 12 | * Total Accepted: 14.3K 13 | * Total Submissions: 41.4K 14 | * Testcase Example: '[1,2,3,1]\n3' 15 | * 16 | * 给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 17 | * 的差的绝对值最大为 k。 18 | * 19 | * 示例 1: 20 | * 21 | * 输入: nums = [1,2,3,1], k = 3 22 | * 输出: true 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: nums = [1,0,1,1], k = 1 27 | * 输出: true 28 | * 29 | * 示例 3: 30 | * 31 | * 输入: nums = [1,2,3,1,2,3], k = 2 32 | * 输出: false 33 | * 34 | */ 35 | func containsNearbyDuplicate(nums []int, k int) bool { 36 | m := map[int]int{} 37 | for i, n := range nums { 38 | if j, ok := m[n]; ok && i - j <= k { 39 | return true 40 | } else { 41 | m[n] = i 42 | } 43 | } 44 | return false 45 | } 46 | 47 | -------------------------------------------------------------------------------- /go/leetcode/22.括号生成.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=22 lang=golang 3 | * 4 | * [22] 括号生成 5 | * 6 | * https://leetcode-cn.com/problems/generate-parentheses/description/ 7 | * 8 | * algorithms 9 | * Medium (70.38%) 10 | * Likes: 385 11 | * Dislikes: 0 12 | * Total Accepted: 24.1K 13 | * Total Submissions: 34.2K 14 | * Testcase Example: '3' 15 | * 16 | * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 17 | * 18 | * 例如,给出 n = 3,生成结果为: 19 | * 20 | * [ 21 | * ⁠ "((()))", 22 | * ⁠ "(()())", 23 | * ⁠ "(())()", 24 | * ⁠ "()(())", 25 | * ⁠ "()()()" 26 | * ] 27 | * 28 | * 29 | */ 30 | 31 | // 树的根节点是左括号,层数是3层,求路径集合,终止条件:左右数递减到0,或者右节点比左节点多 32 | func helper(left int, right int, out string, res *[]string) { 33 | if left > right { // 左剩余比右多,也就是右节点多了,没法匹配 34 | return 35 | } 36 | if left == 0 && right == 0 { 37 | *res = append(*res, out) // 复制值 38 | return 39 | } 40 | if left > 0 { 41 | helper(left-1, right, out+"(", res) 42 | } 43 | if right > 0 { 44 | helper(left, right-1, out+")", res) 45 | } 46 | } 47 | 48 | // 组合题目一般用递归,组合一般可以看成是树结构,用dfs、bfs配合规则求解 49 | func generateParenthesis(n int) []string { 50 | res := []string{} 51 | helper(n, n, "", &res) 52 | return res 53 | } 54 | 55 | -------------------------------------------------------------------------------- /go/leetcode/222.完全二叉树的节点个数.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=222 lang=golang 3 | * 4 | * [222] 完全二叉树的节点个数 5 | * 6 | * https://leetcode-cn.com/problems/count-complete-tree-nodes/description/ 7 | * 8 | * algorithms 9 | * Medium (62.64%) 10 | * Likes: 94 11 | * Dislikes: 0 12 | * Total Accepted: 10.2K 13 | * Total Submissions: 16.2K 14 | * Testcase Example: '[1,2,3,4,5,6]' 15 | * 16 | * 给出一个完全二叉树,求出该树的节点个数。 17 | * 18 | * 说明: 19 | * 20 | * 21 | * 完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 22 | * h 层,则该层包含 1~ 2^h 个节点。 23 | * 24 | * 示例: 25 | * 26 | * 输入: 27 | * ⁠ 1 28 | * ⁠ / \ 29 | * ⁠ 2 3 30 | * ⁠/ \ / 31 | * 4 5 6 32 | * 33 | * 输出: 6 34 | * 35 | */ 36 | 37 | // package leetcode 38 | 39 | // @lc code=start 40 | /** 41 | * Definition for a binary tree node. 42 | * type TreeNode struct { 43 | * Val int 44 | * Left *TreeNode 45 | * Right *TreeNode 46 | * } 47 | */ 48 | 49 | // 对比左右节点,找到满的一侧(个数为2^n-1),然后递归求解不满的一侧,加上顶点就是总数 50 | func countNodes(root *TreeNode) int { 51 | if root == nil { 52 | return 0 53 | } 54 | l := getLevel(root.Left) 55 | r := getLevel(root.Right) 56 | if l == r { // 左侧必然是满的,右侧才会有部分节点在最低层 57 | lc := 0 58 | if l > 0 { 59 | lc = 2<<(l-1) - 1 60 | } 61 | return 1 + lc + countNodes(root.Right) // 顶点+左侧+递归右侧 62 | } 63 | // 右侧必然是满的 64 | rc := 0 65 | if r > 0 { 66 | rc = 2<<(r-1) - 1 67 | } 68 | return 1 + rc + countNodes(root.Left) 69 | } 70 | 71 | func getLevel(root *TreeNode) int { 72 | if root == nil { 73 | return 0 74 | } 75 | l := getLevel(root.Left) 76 | r := getLevel(root.Right) 77 | if l > r { 78 | return 1 + l 79 | } 80 | return 1 + r 81 | } 82 | 83 | // @lc code=end 84 | -------------------------------------------------------------------------------- /go/leetcode/226.翻转二叉树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=226 lang=golang 3 | * 4 | * [226] 翻转二叉树 5 | * 6 | * https://leetcode-cn.com/problems/invert-binary-tree/description/ 7 | * 8 | * algorithms 9 | * Easy (77.86%) 10 | * Likes: 733 11 | * Dislikes: 0 12 | * Total Accepted: 181.4K 13 | * Total Submissions: 232.9K 14 | * Testcase Example: '[4,2,7,1,3,6,9]' 15 | * 16 | * 翻转一棵二叉树。 17 | * 18 | * 示例: 19 | * 20 | * 输入: 21 | * 22 | * ⁠ 4 23 | * ⁠ / \ 24 | * ⁠ 2 7 25 | * ⁠/ \ / \ 26 | * 1 3 6 9 27 | * 28 | * 输出: 29 | * 30 | * ⁠ 4 31 | * ⁠ / \ 32 | * ⁠ 7 2 33 | * ⁠/ \ / \ 34 | * 9 6 3 1 35 | * 36 | * 备注: 37 | * 这个问题是受到 Max Howell 的 原问题 启发的 : 38 | * 39 | * 谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。 40 | * 41 | */ 42 | 43 | // @lc code=start 44 | /** 45 | * Definition for a binary tree node. 46 | * type TreeNode struct { 47 | * Val int 48 | * Left *TreeNode 49 | * Right *TreeNode 50 | * } 51 | */ 52 | func invertTree(root *TreeNode) *TreeNode { 53 | if root == nil { 54 | return root 55 | } 56 | 57 | l := invertTree(root.Right) 58 | r := invertTree(root.Left) 59 | root.Left = l 60 | root.Right = r 61 | return root 62 | } 63 | // @lc code=end 64 | 65 | -------------------------------------------------------------------------------- /go/leetcode/23.合并k个排序链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=23 lang=golang 3 | * 4 | * [23] 合并K个排序链表 5 | */ 6 | /** 7 | * Definition for singly-linked list. 8 | * type ListNode struct { 9 | * Val int 10 | * Next *ListNode 11 | * } 12 | */ 13 | 14 | import ( 15 | "container/heap" 16 | ) 17 | 18 | type srHeap []*ListNode 19 | 20 | func (h *srHeap) Less(i, j int) bool { 21 | return (*h)[i].Val < (*h)[j].Val 22 | } 23 | 24 | func (h *srHeap) Swap(i, j int) { 25 | (*h)[i], (*h)[j] = (*h)[j], (*h)[i] 26 | } 27 | 28 | func (h *srHeap) Len() int { 29 | return len(*h) 30 | } 31 | 32 | func (h *srHeap) Pop() (v interface{}) { 33 | *h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1] 34 | return 35 | } 36 | 37 | func (h *srHeap) Push(v interface{}) { 38 | *h = append(*h, v.(*ListNode)) 39 | } 40 | 41 | // MergeKLists 合并k个有序链表 42 | func mergeKLists(lists []*ListNode) *ListNode { 43 | heads := make(srHeap, 0) 44 | for _, h := range lists { 45 | if h != nil { 46 | heads = append(heads, h) 47 | } 48 | } 49 | heap.Init(&heads) 50 | dummy := &ListNode{} 51 | c := dummy 52 | for len(heads) > 0 { 53 | c.Next = heap.Pop(&heads).(*ListNode) 54 | c = c.Next 55 | if c.Next != nil { 56 | heap.Push(&heads, c.Next) 57 | } 58 | } 59 | return dummy.Next 60 | } 61 | -------------------------------------------------------------------------------- /go/leetcode/230.二叉搜索树中第k小的元素.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=230 lang=golang 3 | * 4 | * [230] 二叉搜索树中第K小的元素 5 | * 6 | * https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/description/ 7 | * 8 | * algorithms 9 | * Medium (72.25%) 10 | * Likes: 302 11 | * Dislikes: 0 12 | * Total Accepted: 74.7K 13 | * Total Submissions: 103.3K 14 | * Testcase Example: '[3,1,4,null,2]\n1' 15 | * 16 | * 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。 17 | * 18 | * 说明: 19 | * 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。 20 | * 21 | * 示例 1: 22 | * 23 | * 输入: root = [3,1,4,null,2], k = 1 24 | * ⁠ 3 25 | * ⁠ / \ 26 | * ⁠1 4 27 | * ⁠ \ 28 | * 2 29 | * 输出: 1 30 | * 31 | * 示例 2: 32 | * 33 | * 输入: root = [5,3,6,2,4,null,null,1], k = 3 34 | * ⁠ 5 35 | * ⁠ / \ 36 | * ⁠ 3 6 37 | * ⁠ / \ 38 | * ⁠ 2 4 39 | * ⁠ / 40 | * ⁠1 41 | * 输出: 3 42 | * 43 | * 进阶: 44 | * 如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数? 45 | * 46 | */ 47 | 48 | // @lc code=start 49 | /** 50 | * Definition for a binary tree node. 51 | * type TreeNode struct { 52 | * Val int 53 | * Left *TreeNode 54 | * Right *TreeNode 55 | * } 56 | */ 57 | func kthSmallest(root *TreeNode, k int) int { 58 | ret := []int{} 59 | walk(root, k, &ret) 60 | if len(ret) >= k { 61 | return ret[k-1] 62 | } 63 | return -1 64 | } 65 | 66 | func walk(root *TreeNode, k int, ret *[]int) { 67 | if root == nil || len(*ret) >= k { 68 | return 69 | } 70 | walk(root.Left, k, ret) 71 | *ret = append(*ret, root.Val) 72 | walk(root.Right, k, ret) 73 | } 74 | // @lc code=end 75 | 76 | -------------------------------------------------------------------------------- /go/leetcode/235.二叉搜索树的最近公共祖先.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=235 lang=golang 3 | * 4 | * [235] 二叉搜索树的最近公共祖先 5 | * 6 | * https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/ 7 | * 8 | * algorithms 9 | * Easy (65.97%) 10 | * Likes: 527 11 | * Dislikes: 0 12 | * Total Accepted: 119.4K 13 | * Total Submissions: 181K 14 | * Testcase Example: '[6,2,8,0,4,7,9,null,null,3,5]\n2\n8' 15 | * 16 | * 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 17 | * 18 | * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 19 | * 的深度尽可能大(一个节点也可以是它自己的祖先)。” 20 | * 21 | * 例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5] 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 示例 1: 28 | * 29 | * 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 30 | * 输出: 6 31 | * 解释: 节点 2 和节点 8 的最近公共祖先是 6。 32 | * 33 | * 34 | * 示例 2: 35 | * 36 | * 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 37 | * 输出: 2 38 | * 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。 39 | * 40 | * 41 | * 42 | * 说明: 43 | * 44 | * 45 | * 所有节点的值都是唯一的。 46 | * p、q 为不同节点且均存在于给定的二叉搜索树中。 47 | * 48 | * 49 | */ 50 | 51 | // @lc code=start 52 | /** 53 | * Definition for a binary tree node. 54 | * type TreeNode struct { 55 | * Val int 56 | * Left *TreeNode 57 | * Right *TreeNode 58 | * } 59 | */ 60 | 61 | func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { 62 | ancestor := root 63 | for { 64 | if p.Val < ancestor.Val && q.Val < ancestor.Val { 65 | ancestor = ancestor.Left 66 | } else if p.Val > ancestor.Val && q.Val > ancestor.Val { 67 | ancestor = ancestor.Right 68 | } else { 69 | break 70 | } 71 | } 72 | return ancestor 73 | } 74 | // @lc code=end 75 | 76 | -------------------------------------------------------------------------------- /go/leetcode/237.删除链表中的节点.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=237 lang=golang 3 | * 4 | * [237] 删除链表中的节点 5 | * 6 | * https://leetcode-cn.com/problems/delete-node-in-a-linked-list/description/ 7 | * 8 | * algorithms 9 | * Easy (73.71%) 10 | * Likes: 358 11 | * Dislikes: 0 12 | * Total Accepted: 33.4K 13 | * Total Submissions: 45.3K 14 | * Testcase Example: '[4,5,1,9]\n5' 15 | * 16 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 17 | * 18 | * 现有一个链表 -- head = [4,5,1,9],它可以表示为: 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 示例 1: 25 | * 26 | * 输入: head = [4,5,1,9], node = 5 27 | * 输出: [4,1,9] 28 | * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 29 | * 30 | * 31 | * 示例 2: 32 | * 33 | * 输入: head = [4,5,1,9], node = 1 34 | * 输出: [4,5,9] 35 | * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9. 36 | * 37 | * 38 | * 39 | * 40 | * 说明: 41 | * 42 | * 43 | * 链表至少包含两个节点。 44 | * 链表中所有节点的值都是唯一的。 45 | * 给定的节点为非末尾节点并且一定是链表中的一个有效节点。 46 | * 不要从你的函数中返回任何结果。 47 | * 48 | * 49 | */ 50 | /** 51 | * Definition for singly-linked list. 52 | * type ListNode struct { 53 | * Val int 54 | * Next *ListNode 55 | * } 56 | */ 57 | func deleteNode(node *ListNode) { 58 | node.Val = node.Next.Val 59 | node.Next = node.Next.Next 60 | } 61 | 62 | -------------------------------------------------------------------------------- /go/leetcode/24.两两交换链表中的节点.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=24 lang=golang 3 | * 4 | * [24] 两两交换链表中的节点 5 | */ 6 | /** 7 | * Definition for singly-linked list. 8 | * type ListNode struct { 9 | * Val int 10 | * Next *ListNode 11 | * } 12 | */ 13 | 14 | // 保存两个全局变量:局部转换头节点和当前节点 15 | func swapPairs(head *ListNode) *ListNode { 16 | dummy := &ListNode{} 17 | dummy.Next = head 18 | curHead := dummy 19 | cur := dummy.Next 20 | for cur != nil && cur.Next != nil { 21 | next := cur.Next // 2, 4 22 | cur.Next = next.Next // 13, 35 23 | next.Next = cur // 213, 435 24 | curHead.Next = next // h213, 21h435 25 | curHead = cur // 21h3, 2143h5 26 | cur = cur.Next // 3, 5 27 | } 28 | return dummy.Next 29 | } 30 | 31 | -------------------------------------------------------------------------------- /go/leetcode/25.k-个一组翻转链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=25 lang=golang 3 | * 4 | * [25] K 个一组翻转链表 5 | * 6 | * https://leetcode-cn.com/problems/reverse-nodes-in-k-group/description/ 7 | * 8 | * algorithms 9 | * Hard (51.73%) 10 | * Likes: 205 11 | * Dislikes: 0 12 | * Total Accepted: 11.7K 13 | * Total Submissions: 22.5K 14 | * Testcase Example: '[1,2,3,4,5]\n2' 15 | * 16 | * 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 17 | * 18 | * k 是一个正整数,它的值小于或等于链表的长度。 19 | * 20 | * 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 21 | * 22 | * 示例 : 23 | * 24 | * 给定这个链表:1->2->3->4->5 25 | * 26 | * 当 k = 2 时,应当返回: 2->1->4->3->5 27 | * 28 | * 当 k = 3 时,应当返回: 3->2->1->4->5 29 | * 30 | * 说明 : 31 | * 32 | * 33 | * 你的算法只能使用常数的额外空间。 34 | * 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 35 | * 36 | * 37 | */ 38 | /** 39 | * Definition for singly-linked list. 40 | * type ListNode struct { 41 | * Val int 42 | * Next *ListNode 43 | * } 44 | */ 45 | 46 | // 原地反转(from, to)之间的链表,不包含from/to 47 | func reverseRange(from *ListNode, to *ListNode) *ListNode { 48 | cur := from.Next 49 | for cur != nil && cur.Next != to { 50 | next := cur.Next // 2 51 | cur.Next = cur.Next.Next // 13 52 | next.Next = from.Next // 213 53 | from.Next = next // h213 54 | } 55 | return cur 56 | } 57 | 58 | func reverseKGroup(head *ListNode, k int) *ListNode { 59 | dummy := &ListNode{} 60 | dummy.Next = head 61 | left := dummy // h 62 | right := dummy.Next // 1 63 | n := 0 64 | for right != nil { // 不判断 right.Next != nil,为了多走一步 65 | right = right.Next // 2, nil 66 | n++ 67 | if n >= k { // 1 68 | left = reverseRange(left, right) // 69 | n = 0 70 | } 71 | } 72 | return dummy.Next 73 | } 74 | 75 | -------------------------------------------------------------------------------- /go/leetcode/257.二叉树的所有路径.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=257 lang=golang 3 | * 4 | * [257] 二叉树的所有路径 5 | * 6 | * https://leetcode-cn.com/problems/binary-tree-paths/description/ 7 | * 8 | * algorithms 9 | * Easy (66.43%) 10 | * Likes: 436 11 | * Dislikes: 0 12 | * Total Accepted: 93.5K 13 | * Total Submissions: 140.7K 14 | * Testcase Example: '[1,2,3,null,5]' 15 | * 16 | * 给定一个二叉树,返回所有从根节点到叶子节点的路径。 17 | * 18 | * 说明: 叶子节点是指没有子节点的节点。 19 | * 20 | * 示例: 21 | * 22 | * 输入: 23 | * 24 | * ⁠ 1 25 | * ⁠/ \ 26 | * 2 3 27 | * ⁠\ 28 | * ⁠ 5 29 | * 30 | * 输出: ["1->2->5", "1->3"] 31 | * 32 | * 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3 33 | * 34 | */ 35 | 36 | // @lc code=start 37 | /** 38 | * Definition for a binary tree node. 39 | * type TreeNode struct { 40 | * Val int 41 | * Left *TreeNode 42 | * Right *TreeNode 43 | * } 44 | */ 45 | 46 | func binaryTreePaths(root *TreeNode) []string { 47 | ret := make([]string, 0) 48 | helper(root, "", &ret) 49 | return ret 50 | } 51 | 52 | func helper(root *TreeNode, path string, ret *[]string) { 53 | if root == nil { 54 | return 55 | } 56 | var newPath string 57 | if path == "" { 58 | newPath = fmt.Sprintf("%d", root.Val) 59 | } else { 60 | newPath = fmt.Sprintf("%s->%d", path, root.Val) 61 | } 62 | if root.Left == nil && root.Right == nil { 63 | *ret = append(*ret, newPath) 64 | return 65 | } 66 | if root.Left != nil { 67 | helper(root.Left, newPath, ret) 68 | } 69 | if root.Right != nil { 70 | helper(root.Right, newPath, ret) 71 | } 72 | } 73 | // @lc code=end 74 | 75 | -------------------------------------------------------------------------------- /go/leetcode/26.删除排序数组中的重复项.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=26 lang=golang 3 | * 4 | * [26] 删除排序数组中的重复项 5 | * 6 | * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/ 7 | * 8 | * algorithms 9 | * Easy (47.37%) 10 | * Likes: 1189 11 | * Dislikes: 0 12 | * Total Accepted: 204.7K 13 | * Total Submissions: 432.1K 14 | * Testcase Example: '[1,1,2]' 15 | * 16 | * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 17 | * 18 | * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 19 | * 20 | * 示例 1: 21 | * 22 | * 给定数组 nums = [1,1,2], 23 | * 24 | * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 25 | * 26 | * 你不需要考虑数组中超出新长度后面的元素。 27 | * 28 | * 示例 2: 29 | * 30 | * 给定 nums = [0,0,1,1,1,2,2,3,3,4], 31 | * 32 | * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 33 | * 34 | * 你不需要考虑数组中超出新长度后面的元素。 35 | * 36 | * 37 | * 说明: 38 | * 39 | * 为什么返回数值是整数,但输出的答案是数组呢? 40 | * 41 | * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 42 | * 43 | * 你可以想象内部操作如下: 44 | * 45 | * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 46 | * int len = removeDuplicates(nums); 47 | * 48 | * // 在函数里修改输入数组对于调用者是可见的。 49 | * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 50 | * for (int i = 0; i < len; i++) { 51 | * print(nums[i]); 52 | * } 53 | * 54 | * 55 | */ 56 | 57 | // @lc code=start 58 | func removeDuplicates(nums []int) int { 59 | if len(nums) == 0 { 60 | return 0 61 | } 62 | i := 0 63 | for j := 1; j < len(nums); j++ { 64 | if nums[i] != nums[j] { 65 | i++ 66 | nums[i] = nums[j] 67 | } 68 | } 69 | return i+1 70 | } 71 | // @lc code=end 72 | 73 | -------------------------------------------------------------------------------- /go/leetcode/260.只出现一次的数字-iii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=260 lang=golang 3 | * 4 | * [260] 只出现一次的数字 III 5 | * 6 | * https://leetcode-cn.com/problems/single-number-iii/description/ 7 | * 8 | * algorithms 9 | * Medium (67.85%) 10 | * Likes: 141 11 | * Dislikes: 0 12 | * Total Accepted: 10.9K 13 | * Total Submissions: 16.1K 14 | * Testcase Example: '[1,2,1,3,2,5]' 15 | * 16 | * 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。 17 | * 18 | * 示例 : 19 | * 20 | * 输入: [1,2,1,3,2,5] 21 | * 输出: [3,5] 22 | * 23 | * 注意: 24 | * 25 | * 26 | * 结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。 27 | * 你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现? 28 | * 29 | * 30 | */ 31 | 32 | // @lc code=start 33 | // 先将数组整体异或得到两个不同数字的异或结果,因为这两个数字不同,所以异或结果必然不为0 34 | // 异或结果中1的位就是两者不同的位,也就是某个数为1的位,找一个这样的位然后将其他位置为0,得到一个flag 35 | // 遍历数组,用这个flag去与,如果不为0则表示这个位是1,为0则表示这个位是0,这样就将不同的两个数分在两个组里面了 36 | // 对这两个组分别组内异或,就能得到两个不同的数字 37 | func singleNumber(nums []int) []int { 38 | diff := nums[0] 39 | for i := 1; i < len(nums); i++ { 40 | diff ^= nums[i] 41 | } 42 | diff &= -diff // 保留从右往左第一个1,其他位设为0 43 | ret := make([]int, 2) 44 | for _, num := range nums { 45 | if num & diff == 0 { 46 | ret[0] ^= num 47 | } else { 48 | ret[1] ^= num 49 | } 50 | } 51 | return ret 52 | } 53 | // @lc code=end 54 | 55 | -------------------------------------------------------------------------------- /go/leetcode/268.缺失数字.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=268 lang=golang 3 | * 4 | * [268] 缺失数字 5 | * 6 | * https://leetcode-cn.com/problems/missing-number/description/ 7 | * 8 | * algorithms 9 | * Easy (53.17%) 10 | * Likes: 185 11 | * Dislikes: 0 12 | * Total Accepted: 39.5K 13 | * Total Submissions: 74.2K 14 | * Testcase Example: '[3,0,1]' 15 | * 16 | * 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: [3,0,1] 21 | * 输出: 2 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: [9,6,4,2,3,5,7,0,1] 27 | * 输出: 8 28 | * 29 | * 30 | * 说明: 31 | * 你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现? 32 | * 33 | */ 34 | 35 | // package leetcode 36 | 37 | // 假设0-n都在序列里面,那么根据求和公式可以算出和 38 | // 另外可以遍历序列求和,两个和之差就是缺失的数字 39 | 40 | // @lc code=start 41 | func missingNumber(nums []int) int { 42 | sum := 0 43 | // 算实际的和 44 | for i := 0; i < len(nums); i++ { 45 | sum += nums[i] 46 | } 47 | // 根据等差数据求和公式算出1~n的和 48 | sumN := 0.5 * float32(1+len(nums)) * float32(len(nums)) 49 | return int(sumN) - sum 50 | } 51 | 52 | // @lc code=end 53 | -------------------------------------------------------------------------------- /go/leetcode/27.移除元素.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=27 lang=golang 3 | * 4 | * [27] 移除元素 5 | * 6 | * https://leetcode-cn.com/problems/remove-element/description/ 7 | * 8 | * algorithms 9 | * Easy (57.74%) 10 | * Likes: 500 11 | * Dislikes: 0 12 | * Total Accepted: 149.1K 13 | * Total Submissions: 258.1K 14 | * Testcase Example: '[3,2,2,3]\n3' 15 | * 16 | * 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 17 | * 18 | * 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 19 | * 20 | * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 21 | * 22 | * 23 | * 24 | * 示例 1: 25 | * 26 | * 给定 nums = [3,2,2,3], val = 3, 27 | * 28 | * 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 29 | * 30 | * 你不需要考虑数组中超出新长度后面的元素。 31 | * 32 | * 33 | * 示例 2: 34 | * 35 | * 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 36 | * 37 | * 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 38 | * 39 | * 注意这五个元素可为任意顺序。 40 | * 41 | * 你不需要考虑数组中超出新长度后面的元素。 42 | * 43 | * 44 | * 45 | * 46 | * 说明: 47 | * 48 | * 为什么返回数值是整数,但输出的答案是数组呢? 49 | * 50 | * 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 51 | * 52 | * 你可以想象内部操作如下: 53 | * 54 | * // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝 55 | * int len = removeElement(nums, val); 56 | * 57 | * // 在函数里修改输入数组对于调用者是可见的。 58 | * // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。 59 | * for (int i = 0; i < len; i++) { 60 | * print(nums[i]); 61 | * } 62 | * 63 | * 64 | */ 65 | 66 | // @lc code=start 67 | func removeElement(nums []int, val int) int { 68 | if len(nums) <= 0 { 69 | return 0 70 | } 71 | i := 0 72 | for j := 0; j < len(nums); j++ { 73 | if nums[j] != val { 74 | nums[i] = nums[j] 75 | i++ 76 | } 77 | } 78 | return i 79 | } 80 | // @lc code=end 81 | 82 | -------------------------------------------------------------------------------- /go/leetcode/28.implement-strstr.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=28 lang=golang 3 | * 4 | * [28] 实现strStr() 5 | * 6 | * https://leetcode-cn.com/problems/implement-strstr/description/ 7 | * 8 | * algorithms 9 | * Easy (37.38%) 10 | * Total Accepted: 34.5K 11 | * Total Submissions: 92.3K 12 | * Testcase Example: '"hello"\n"ll"' 13 | * 14 | * 实现 strStr() 函数。 15 | * 16 | * 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 17 | * (从0开始)。如果不存在,则返回  -1。 18 | * 19 | * 示例 1: 20 | * 21 | * 输入: haystack = "hello", needle = "ll" 22 | * 输出: 2 23 | * 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: haystack = "aaaaa", needle = "bba" 28 | * 输出: -1 29 | * 30 | * 31 | * 说明: 32 | * 33 | * 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 34 | * 35 | * 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 36 | * 37 | */ 38 | func strStr(haystack string, needle string) int { 39 | if len(needle) == 0 { 40 | return 0 41 | } 42 | 43 | for i := 0; i < len(haystack); i++ { 44 | isEqual := true 45 | if len(haystack)-i < len(needle) { 46 | isEqual = false 47 | break 48 | } 49 | for j := 0; j < len(needle); j++ { 50 | if haystack[i+j] != needle[j] { 51 | isEqual = false 52 | break 53 | } 54 | } 55 | if isEqual { 56 | return i 57 | } 58 | } 59 | return -1 60 | } 61 | -------------------------------------------------------------------------------- /go/leetcode/287.寻找重复数.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=287 lang=golang 3 | * 4 | * [287] 寻找重复数 5 | * 6 | * https://leetcode-cn.com/problems/find-the-duplicate-number/description/ 7 | * 8 | * algorithms 9 | * Medium (61.75%) 10 | * Likes: 328 11 | * Dislikes: 0 12 | * Total Accepted: 26.4K 13 | * Total Submissions: 42.8K 14 | * Testcase Example: '[1,3,4,2,2]' 15 | * 16 | * 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 17 | * n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 18 | * 19 | * 示例 1: 20 | * 21 | * 输入: [1,3,4,2,2] 22 | * 输出: 2 23 | * 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: [3,1,3,4,2] 28 | * 输出: 3 29 | * 30 | * 31 | * 说明: 32 | * 33 | * 34 | * 不能更改原数组(假设数组是只读的)。 35 | * 只能使用额外的 O(1) 的空间。 36 | * 时间复杂度小于 O(n^2) 。 37 | * 数组中只有一个重复的数字,但它可能不止重复出现一次。 38 | * 39 | * 40 | */ 41 | // 题目中的数字都是1~n,假设没有重复,那按中点分割每一侧的数字个数=max-min 42 | // 如果存在重复,那么有n>max-min,不断二分这个mid可以找到目标值 43 | 44 | // @lc code=start 45 | func findDuplicate(nums []int) int { 46 | left, right := 1, len(nums) 47 | for left < right { 48 | mid := left + (right - left) / 2 49 | count := 0 50 | for _, num := range nums { 51 | if num <= mid { 52 | count++ 53 | } 54 | } 55 | if count <= mid { 56 | left = mid + 1 57 | } else { 58 | right = mid 59 | } 60 | } 61 | return left 62 | } 63 | // @lc code=end 64 | 65 | -------------------------------------------------------------------------------- /go/leetcode/292.nim-游戏.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=292 lang=golang 3 | * 4 | * [292] Nim 游戏 5 | * 6 | * https://leetcode-cn.com/problems/nim-game/description/ 7 | * 8 | * algorithms 9 | * Easy (69.56%) 10 | * Likes: 231 11 | * Dislikes: 0 12 | * Total Accepted: 31.2K 13 | * Total Submissions: 44.9K 14 | * Testcase Example: '4' 15 | * 16 | * 你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。 17 | * 18 | * 你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。 19 | * 20 | * 示例: 21 | * 22 | * 输入: 4 23 | * 输出: false 24 | * 解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛; 25 | * 因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。 26 | * 27 | * 28 | */ 29 | 30 | // @lc code=start 31 | func canWinNim(n int) bool { 32 | return n % 4 != 0 33 | } 34 | // @lc code=end 35 | 36 | -------------------------------------------------------------------------------- /go/leetcode/3.无重复字符的最长子串.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=3 lang=golang 3 | * 4 | * [3] 无重复字符的最长子串 5 | * 6 | * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/description/ 7 | * 8 | * algorithms 9 | * Medium (28.06%) 10 | * Total Accepted: 79.6K 11 | * Total Submissions: 282.8K 12 | * Testcase Example: '"abcabcbb"' 13 | * 14 | * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 15 | * 16 | * 示例 1: 17 | * 18 | * 输入: "abcabcbb" 19 | * 输出: 3 20 | * 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 21 | * 22 | * 23 | * 示例 2: 24 | * 25 | * 输入: "bbbbb" 26 | * 输出: 1 27 | * 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 28 | * 29 | * 30 | * 示例 3: 31 | * 32 | * 输入: "pwwkew" 33 | * 输出: 3 34 | * 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 35 | * 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 36 | * 37 | * 38 | */ 39 | func lengthOfLongestSubstring(s string) int { 40 | m := map[rune]int{} 41 | i := 0 42 | max := 0 43 | for j, c := range s { 44 | if v, exist := m[c]; exist && v >= i { 45 | i = v + 1 46 | } 47 | m[c] = j 48 | if j-i+1 > max { 49 | max = j - i + 1 50 | } 51 | } 52 | return max 53 | } 54 | 55 | -------------------------------------------------------------------------------- /go/leetcode/300.最长上升子序列.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=300 lang=golang 3 | * 4 | * [300] 最长上升子序列 5 | * 6 | * https://leetcode-cn.com/problems/longest-increasing-subsequence/description/ 7 | * 8 | * algorithms 9 | * Medium (43.34%) 10 | * Likes: 360 11 | * Dislikes: 0 12 | * Total Accepted: 38.6K 13 | * Total Submissions: 88.7K 14 | * Testcase Example: '[10,9,2,5,3,7,101,18]' 15 | * 16 | * 给定一个无序的整数数组,找到其中最长上升子序列的长度。 17 | * 18 | * 示例: 19 | * 20 | * 输入: [10,9,2,5,3,7,101,18] 21 | * 输出: 4 22 | * 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 23 | * 24 | * 说明: 25 | * 26 | * 27 | * 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 28 | * 你算法的时间复杂度应该为 O(n^2) 。 29 | * 30 | * 31 | * 进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗? 32 | * 33 | */ 34 | 35 | /* 36 | * 求极值第一反应是动态规划,状态转移方程是dp[i]=max(dp[i], nums[i]>nums[j] ? dp[j]+1 : dp[j]) 37 | * 其中,dp[i]表示0~i之间最长上升子序列长,0 b { 65 | return a 66 | } 67 | return b 68 | } 69 | 70 | // @lc code=end 71 | -------------------------------------------------------------------------------- /go/leetcode/31.下一个排列.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=31 lang=golang 3 | * 4 | * [31] 下一个排列 5 | */ 6 | 7 | func swap(nums []int, i int, j int) { 8 | tmp := nums[j] 9 | nums[j] = nums[i] 10 | nums[i] = tmp 11 | } 12 | 13 | func reverse(nums []int, i int, j int) { 14 | for i < j { 15 | swap(nums, i, j) 16 | i++ 17 | j-- 18 | } 19 | } 20 | 21 | func nextPermutation(nums []int) { 22 | // 1 2 4 7 5 3 1 23 | // 1 2 5 7 4 3 1 24 | // 1 2 5 1 3 4 7 25 | length := len(nums) 26 | if length < 2 { 27 | return 28 | } 29 | var i, j int 30 | for i = length - 2; i >= 0; i-- { 31 | if nums[i] < nums[i+1] { 32 | for j = length-1; j > i; j-- { 33 | if nums[j] > nums[i] { 34 | break 35 | } 36 | } 37 | swap(nums, i, j) 38 | reverse(nums, i+1, length-1) 39 | break 40 | } 41 | } 42 | if i < 0 { 43 | reverse(nums, 0, length-1) 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /go/leetcode/319.灯泡开关.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=319 lang=golang 3 | * 4 | * [319] 灯泡开关 5 | * 6 | * https://leetcode-cn.com/problems/bulb-switcher/description/ 7 | * 8 | * algorithms 9 | * Medium (43.63%) 10 | * Likes: 69 11 | * Dislikes: 0 12 | * Total Accepted: 6K 13 | * Total Submissions: 13.7K 14 | * Testcase Example: '3' 15 | * 16 | * 初始时有 n 个灯泡关闭。 第 1 轮,你打开所有的灯泡。 第 2 轮,每两个灯泡你关闭一次。 第 3 17 | * 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i 轮,每 i 个灯泡切换一次开关。 对于第 n 轮,你只切换最后一个灯泡的开关。 18 | * 找出 n 轮后有多少个亮着的灯泡。 19 | * 20 | * 示例: 21 | * 22 | * 输入: 3 23 | * 输出: 1 24 | * 解释: 25 | * 初始时, 灯泡状态 [关闭, 关闭, 关闭]. 26 | * 第一轮后, 灯泡状态 [开启, 开启, 开启]. 27 | * 第二轮后, 灯泡状态 [开启, 关闭, 开启]. 28 | * 第三轮后, 灯泡状态 [开启, 关闭, 关闭]. 29 | * 30 | * 你应该返回 1,因为只有一个灯泡还亮着。 31 | * 32 | * 33 | */ 34 | 35 | /* 36 | * 注意审题,是n个灯泡经过n轮,先取一个n看看,比如n=16: 37 | * 第1个灯泡,第1轮改变状态,一直亮着 38 | * 第2个灯泡,第1、2轮改变状态,灭掉 39 | * 第3个灯泡,第1、3轮改变状态,灭掉 40 | * 第4个灯泡,第1、2、4轮改变状态,亮着 41 | * ... 42 | * 第13个灯泡,第1、13轮会切换状态,最后灭了 43 | * 第14个灯泡,第1、2、7、14轮会切换状态,最后灭了 44 | * 第15个灯泡,第1、3、5、15轮会切换状态,最后灭了 45 | * 第16个灯泡,第1、2、4、8、16轮会切换状态,也就是找出所有因子,最后是亮着到的 46 | * 对于第k个灯泡来说,也就是找出1~k的因子,数量为奇数则亮着 47 | * 再看下规律,只有1、4、9、16亮着,也就是完全平方数才亮着,就改为求n以内的完全平方数数量 48 | */ 49 | 50 | 51 | // @lc code=start 52 | func bulbSwitch(n int) int { 53 | res := 1 54 | for res * res <= n { 55 | res++ 56 | } 57 | return res - 1 58 | } 59 | // @lc code=end 60 | 61 | -------------------------------------------------------------------------------- /go/leetcode/32.最长有效括号.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=32 lang=golang 3 | * 4 | * [32] 最长有效括号 5 | * 6 | * https://leetcode-cn.com/problems/longest-valid-parentheses/description/ 7 | * 8 | * algorithms 9 | * Hard (27.02%) 10 | * Likes: 230 11 | * Dislikes: 0 12 | * Total Accepted: 11.4K 13 | * Total Submissions: 42K 14 | * Testcase Example: '"(()"' 15 | * 16 | * 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: "(()" 21 | * 输出: 2 22 | * 解释: 最长有效括号子串为 "()" 23 | * 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: ")()())" 28 | * 输出: 4 29 | * 解释: 最长有效括号子串为 "()()" 30 | * 31 | * 32 | */ 33 | 34 | // 括号匹配一般使用栈来做,而且在括号匹配中,只有左括号才能入栈,那么栈中元素的值已经不重要了,只有有值就说明有左括号 35 | // 回到这个题目,则可以将左括号的序号入栈,匹配时根据序号差确定子串长度 36 | // 出栈之后栈空了,所以需要一个变量存括号起始位置:()()、start=0 37 | // 出栈后栈顶的元素是未匹配到的左括号位置,也就是有效子串的起始位置 38 | func longestValidParentheses(s string) int { 39 | // ()((() 2 40 | stack := []int{} 41 | left := "("[0] 42 | max := 0 43 | start := 0 44 | for i := range s { 45 | if s[i] == left { 46 | stack = append(stack, i) // 左括号直接入栈 47 | } else if len(stack) <= 0 { // 空栈遇到右括号,有效括号在这里截断,下标更新 48 | start = i + 1 49 | } else { // 非空,右括号能匹配到左括号 50 | stack = stack[:len(stack)-1] 51 | var tmp int 52 | if len(stack) <= 0 { // 取出之后栈空了,那就从有效下标开始 53 | tmp = i - start + 1 54 | } else { 55 | tmp = i - stack[len(stack)-1] // 对应(()()这种情况,栈顶元素是有效子串的起始位置 56 | } 57 | if tmp > max { 58 | max = tmp 59 | } 60 | } 61 | } 62 | return max 63 | } 64 | 65 | -------------------------------------------------------------------------------- /go/leetcode/322.零钱兑换.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=322 lang=golang 3 | * 4 | * [322] 零钱兑换 5 | * 6 | * https://leetcode-cn.com/problems/coin-change/description/ 7 | * 8 | * algorithms 9 | * Medium (36.38%) 10 | * Likes: 280 11 | * Dislikes: 0 12 | * Total Accepted: 30.2K 13 | * Total Submissions: 83K 14 | * Testcase Example: '[1,2,5]\n11' 15 | * 16 | * 给定不同面额的硬币 coins 和一个总金额 17 | * amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 18 | * 19 | * 示例 1: 20 | * 21 | * 输入: coins = [1, 2, 5], amount = 11 22 | * 输出: 3 23 | * 解释: 11 = 5 + 5 + 1 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: coins = [2], amount = 3 28 | * 输出: -1 29 | * 30 | * 说明: 31 | * 你可以认为每种硬币的数量是无限的。 32 | * 33 | */ 34 | 35 | // 求极值一般会考虑使用动态规划。用dp[i]表示i元的最少硬币兑换数,则状态转移方程: 36 | // dp[i] = min(dp[i], dp[i-coins[x]]+1) 37 | // dp有两种模式,一种在迭代的时候增加记忆数组,另外一种是上来先算记忆数组 38 | // PS: 这个兑换有个特例,就是各种硬币是倍数关系的时候,这个时候退化成贪婪模式 39 | 40 | // @lc code=start 41 | func min(a, b int) int { 42 | if a < b { 43 | return a 44 | } 45 | return b 46 | } 47 | 48 | func coinChange(coins []int, amount int) int { 49 | dp := make([]int, amount+1) 50 | for i := 0; i < amount+1; i++ { 51 | // 假设硬币最小是1元,所以最大是amount个硬币 52 | // 但是现在不一定有1元硬币,所以初值设置成amount+1就可以保证进入到-1的分支 53 | dp[i] = amount + 1 54 | } 55 | dp[0] = 0 56 | for i := 1; i <= amount; i++ { 57 | for j := 0; j < len(coins); j++ { 58 | if coins[j] <= i { 59 | dp[i] = min(dp[i], dp[i-coins[j]]+1) 60 | } 61 | } 62 | } 63 | if dp[amount] > amount { 64 | return -1 65 | } 66 | return dp[amount] 67 | } 68 | // @lc code=end 69 | 70 | -------------------------------------------------------------------------------- /go/leetcode/328.奇偶链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=328 lang=golang 3 | * 4 | * [328] 奇偶链表 5 | * 6 | * https://leetcode-cn.com/problems/odd-even-linked-list/description/ 7 | * 8 | * algorithms 9 | * Medium (56.54%) 10 | * Likes: 62 11 | * Dislikes: 0 12 | * Total Accepted: 10.5K 13 | * Total Submissions: 18.6K 14 | * Testcase Example: '[1,2,3,4,5]' 15 | * 16 | * 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。 17 | * 18 | * 请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。 19 | * 20 | * 示例 1: 21 | * 22 | * 输入: 1->2->3->4->5->NULL 23 | * 输出: 1->3->5->2->4->NULL 24 | * 25 | * 26 | * 示例 2: 27 | * 28 | * 输入: 2->1->3->5->6->4->7->NULL 29 | * 输出: 2->3->6->7->1->5->4->NULL 30 | * 31 | * 说明: 32 | * 33 | * 34 | * 应当保持奇数节点和偶数节点的相对顺序。 35 | * 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。 36 | * 37 | * 38 | */ 39 | /** 40 | * Definition for singly-linked list. 41 | * type ListNode struct { 42 | * Val int 43 | * Next *ListNode 44 | * } 45 | */ 46 | func oddEvenList(head *ListNode) *ListNode { 47 | // h123456 48 | // h132456 49 | // h135246 50 | // h13572468 51 | // 两个指针分别指向奇偶队尾 52 | // i表示序列号,用以判断奇偶 53 | dummy := &ListNode{} 54 | dummy.Next = head 55 | cur := dummy.Next 56 | oddEnd := dummy.Next 57 | for cur != nil && cur.Next != nil && cur.Next.Next != nil { 58 | c1 := cur.Next // 2, 4 59 | c2 := cur.Next.Next // 3, 5 60 | evenStart := oddEnd.Next // 2, 2 61 | oddEnd.Next = c2 // 1>3, 135 62 | c1.Next = c2.Next // 2>4, 4>6 63 | oddEnd = oddEnd.Next // 3, 5 64 | oddEnd.Next = evenStart // 135246 65 | cur = c1 // 4 66 | } 67 | return dummy.Next 68 | } 69 | 70 | -------------------------------------------------------------------------------- /go/leetcode/33.搜索旋转排序数组.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=33 lang=golang 3 | * 4 | * [33] 搜索旋转排序数组 5 | * 6 | * https://leetcode-cn.com/problems/search-in-rotated-sorted-array/description/ 7 | * 8 | * algorithms 9 | * Medium (36.68%) 10 | * Likes: 253 11 | * Dislikes: 0 12 | * Total Accepted: 25.8K 13 | * Total Submissions: 70.4K 14 | * Testcase Example: '[4,5,6,7,0,1,2]\n0' 15 | * 16 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 17 | * 18 | * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 19 | * 20 | * 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 21 | * 22 | * 你可以假设数组中不存在重复的元素。 23 | * 24 | * 你的算法时间复杂度必须是 O(log n) 级别。 25 | * 26 | * 示例 1: 27 | * 28 | * 输入: nums = [4,5,6,7,0,1,2], target = 0 29 | * 输出: 4 30 | * 31 | * 32 | * 示例 2: 33 | * 34 | * 输入: nums = [4,5,6,7,0,1,2], target = 3 35 | * 输出: -1 36 | * 37 | */ 38 | 39 | // O(log n)级别的时间复杂度,第一反应就是二分查找了 40 | // 因为有序数组在某点上旋转了,所以二分查找还需要根据旋转特性来定 41 | func search(nums []int, target int) int { 42 | n := len(nums) 43 | if n <= 0 { 44 | return -1 45 | } 46 | left := 0 47 | right := n - 1 // 包括右侧 48 | for left <= right { // ==表示最后一个 49 | mid := left + (right-left)/2 50 | if nums[mid] == target { 51 | return mid 52 | } 53 | if nums[mid] >= nums[left] { // 左..中 54 | if target >= nums[left] && target < nums[mid] { // 左..target..中 55 | right = mid - 1 // =mid已经返回 56 | } else { // 两种可能target..左..右、左..右..target,都在右边 57 | left = mid + 1 // =mid已经返回 58 | } 59 | } else { // 旋转点在左侧,7..4..8 60 | if target <= nums[right] && target > nums[mid] { 61 | left = mid + 1 62 | } else { 63 | right = mid - 1 64 | } 65 | } 66 | } 67 | return -1 68 | } 69 | 70 | -------------------------------------------------------------------------------- /go/leetcode/34.在排序数组中查找元素的第一个和最后一个位置.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=34 lang=golang 3 | * 4 | * [34] 在排序数组中查找元素的第一个和最后一个位置 5 | * 6 | * https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/description/ 7 | * 8 | * algorithms 9 | * Medium (36.82%) 10 | * Likes: 147 11 | * Dislikes: 0 12 | * Total Accepted: 22.4K 13 | * Total Submissions: 60.9K 14 | * Testcase Example: '[5,7,7,8,8,10]\n8' 15 | * 16 | * 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 17 | * 18 | * 你的算法时间复杂度必须是 O(log n) 级别。 19 | * 20 | * 如果数组中不存在目标值,返回 [-1, -1]。 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: nums = [5,7,7,8,8,10], target = 8 25 | * 输出: [3,4] 26 | * 27 | * 示例 2: 28 | * 29 | * 输入: nums = [5,7,7,8,8,10], target = 6 30 | * 输出: [-1,-1] 31 | * 32 | */ 33 | 34 | // @lc code=start 35 | // 两次二分查找,分别找左右边界 36 | func searchRange(nums []int, target int) []int { 37 | ret := []int{-1, -1} 38 | n := len(nums) 39 | if n <= 0 { 40 | return ret 41 | } 42 | left := 0 43 | right := n 44 | // 找左边界,也就是找左侧第一个target的位置,从0往右收敛 45 | for left < right { 46 | mid := left + (right - left) / 2 47 | if nums[mid] < target { 48 | left = mid + 1 49 | } else { 50 | right = mid // 要找左边界,当中间大于等于目标值的时候,左边界在左侧 51 | } 52 | } 53 | if right >= n || nums[right] > target { 54 | return ret 55 | } 56 | ret[0] = right 57 | // 找右边界,也就是找右侧最后一个target的位置,从end往左收敛 58 | left = 0 59 | right = n 60 | for left < right { 61 | mid := left + (right - left) / 2 62 | if nums[mid] <= target { // 在找左边界的时候已经判断了是否有解,所以 right >= target 63 | left = mid + 1 64 | } else { 65 | right = mid 66 | } 67 | } 68 | ret[1] = right - 1 69 | return ret 70 | } 71 | // @lc code=end 72 | 73 | -------------------------------------------------------------------------------- /go/leetcode/349.两个数组的交集.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=349 lang=golang 3 | * 4 | * [349] 两个数组的交集 5 | * 6 | * https://leetcode-cn.com/problems/intersection-of-two-arrays/description/ 7 | * 8 | * algorithms 9 | * Easy (65.69%) 10 | * Likes: 128 11 | * Dislikes: 0 12 | * Total Accepted: 33.9K 13 | * Total Submissions: 51.2K 14 | * Testcase Example: '[1,2,2,1]\n[2,2]' 15 | * 16 | * 给定两个数组,编写一个函数来计算它们的交集。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: nums1 = [1,2,2,1], nums2 = [2,2] 21 | * 输出: [2] 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 27 | * 输出: [9,4] 28 | * 29 | * 说明: 30 | * 31 | * 32 | * 输出结果中的每个元素一定是唯一的。 33 | * 我们可以不考虑输出结果的顺序。 34 | * 35 | * 36 | */ 37 | func intersection(nums1 []int, nums2 []int) []int { 38 | m1 := map[int]bool{} 39 | for _, el := range nums1 { 40 | m1[el] = true 41 | } 42 | m2 := map[int]bool{} 43 | for _, el := range nums2 { 44 | if m1[el] { 45 | m2[el] = true 46 | } 47 | } 48 | ret := []int{} 49 | for k, _ := range m2 { 50 | ret = append(ret, k) 51 | } 52 | return ret 53 | } 54 | 55 | -------------------------------------------------------------------------------- /go/leetcode/35.search-insert-position.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=35 lang=golang 3 | * 4 | * [35] 搜索插入位置 5 | * 6 | * https://leetcode-cn.com/problems/search-insert-position/description/ 7 | * 8 | * algorithms 9 | * Easy (42.54%) 10 | * Total Accepted: 28.6K 11 | * Total Submissions: 67.2K 12 | * Testcase Example: '[1,3,5,6]\n5' 13 | * 14 | * 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 15 | * 16 | * 你可以假设数组中无重复元素。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: [1,3,5,6], 5 21 | * 输出: 2 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: [1,3,5,6], 2 27 | * 输出: 1 28 | * 29 | * 30 | * 示例 3: 31 | * 32 | * 输入: [1,3,5,6], 7 33 | * 输出: 4 34 | * 35 | * 36 | * 示例 4: 37 | * 38 | * 输入: [1,3,5,6], 0 39 | * 输出: 0 40 | * 41 | * 42 | */ 43 | func searchInsert(nums []int, target int) int { 44 | l, r := 0, len(nums)-1 45 | for l <= r { 46 | m := l + (r-l)/2 47 | if nums[m] < target { 48 | l = m + 1 49 | } else { 50 | r = m - 1 51 | } 52 | } 53 | return l 54 | } 55 | -------------------------------------------------------------------------------- /go/leetcode/350.两个数组的交集-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=350 lang=golang 3 | * 4 | * [350] 两个数组的交集 II 5 | * 6 | * https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/description/ 7 | * 8 | * algorithms 9 | * Easy (44.00%) 10 | * Likes: 188 11 | * Dislikes: 0 12 | * Total Accepted: 48.1K 13 | * Total Submissions: 108.5K 14 | * Testcase Example: '[1,2,2,1]\n[2,2]' 15 | * 16 | * 给定两个数组,编写一个函数来计算它们的交集。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: nums1 = [1,2,2,1], nums2 = [2,2] 21 | * 输出: [2,2] 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 27 | * 输出: [4,9] 28 | * 29 | * 说明: 30 | * 31 | * 32 | * 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 33 | * 我们可以不考虑输出结果的顺序。 34 | * 35 | * 36 | * 进阶: 37 | * 38 | * 39 | * 如果给定的数组已经排好序呢?你将如何优化你的算法? 40 | * 如果 nums1 的大小比 nums2 小很多,哪种方法更优? 41 | * 如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办? 42 | * 43 | * 44 | */ 45 | 46 | // @lc code=start 47 | func intersect(nums1 []int, nums2 []int) []int { 48 | m1 := map[int]int{} 49 | for _, el := range nums1 { 50 | m1[el] += 1 51 | } 52 | m2 := map[int]int{} 53 | for _, el := range nums2 { 54 | if m1[el] > 0 { 55 | m2[el] += 1 56 | } 57 | } 58 | ret := []int{} 59 | for k, v2 := range m2 { 60 | if v2 > m1[k] { 61 | v2 = m1[k] 62 | } 63 | for i := 0; i < v2; i++ { 64 | ret = append(ret, k) 65 | } 66 | } 67 | return ret 68 | } 69 | // @lc code=end 70 | 71 | -------------------------------------------------------------------------------- /go/leetcode/38.count-and-say.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=38 lang=golang 3 | * 4 | * [38] 报数 5 | * 6 | * https://leetcode-cn.com/problems/count-and-say/description/ 7 | * 8 | * algorithms 9 | * Easy (47.98%) 10 | * Total Accepted: 20.4K 11 | * Total Submissions: 42.6K 12 | * Testcase Example: '1' 13 | * 14 | * 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下: 15 | * 16 | * 1. 1 17 | * 2. 11 18 | * 3. 21 19 | * 4. 1211 20 | * 5. 111221 21 | * 22 | * 23 | * 1 被读作  "one 1"  ("一个一") , 即 11。 24 | * 11 被读作 "two 1s" ("两个一"), 即 21。 25 | * 21 被读作 "one 2",  "one 1" ("一个二" ,  "一个一") , 即 1211。 26 | * 27 | * 给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。 28 | * 29 | * 注意:整数顺序将表示为一个字符串。 30 | * 31 | * 32 | * 33 | * 示例 1: 34 | * 35 | * 输入: 1 36 | * 输出: "1" 37 | * 38 | * 39 | * 示例 2: 40 | * 41 | * 输入: 4 42 | * 输出: "1211" 43 | * 44 | * 45 | */ 46 | func countAndSay(n int) string { 47 | 48 | } 49 | -------------------------------------------------------------------------------- /go/leetcode/39.组合总和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=39 lang=golang 3 | * 4 | * [39] 组合总和 5 | * 6 | * https://leetcode-cn.com/problems/combination-sum/description/ 7 | * 8 | * algorithms 9 | * Medium (64.93%) 10 | * Likes: 284 11 | * Dislikes: 0 12 | * Total Accepted: 21.6K 13 | * Total Submissions: 33K 14 | * Testcase Example: '[2,3,6,7]\n7' 15 | * 16 | * 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 17 | * 18 | * candidates 中的数字可以无限制重复被选取。 19 | * 20 | * 说明: 21 | * 22 | * 23 | * 所有数字(包括 target)都是正整数。 24 | * 解集不能包含重复的组合。 25 | * 26 | * 27 | * 示例 1: 28 | * 29 | * 输入: candidates = [2,3,6,7], target = 7, 30 | * 所求解集为: 31 | * [ 32 | * ⁠ [7], 33 | * ⁠ [2,2,3] 34 | * ] 35 | * 36 | * 37 | * 示例 2: 38 | * 39 | * 输入: candidates = [2,3,5], target = 8, 40 | * 所求解集为: 41 | * [ 42 | * [2,2,2,2], 43 | * [2,3,3], 44 | * [3,5] 45 | * ] 46 | * 47 | */ 48 | 49 | func combinationSum(candidates []int, target int) [][]int { 50 | s := &solution{ 51 | arr: candidates, 52 | out: []int{}, 53 | res: [][]int{}, 54 | } 55 | s.helper(target, 0) 56 | return s.res 57 | } 58 | 59 | type solution struct { 60 | arr []int 61 | out []int 62 | res [][]int 63 | } 64 | 65 | // 求所有解的组合一般可以考虑使用递归实现 66 | // 先往解集合中添加某个元素,递归后如果超过限制则回退,恰好符合则将解加入结果集,若未到达限制则继续尝试添加。 67 | // 由于本题已经限定无重复元素,且元素可以重复选取,那么就是每次先递归同一个元素 68 | func (s *solution) helper(target, start int) { 69 | if target < 0 { 70 | return 71 | } 72 | if target == 0 { 73 | s.res = append(s.res, append([]int{}, s.out...)) 74 | return 75 | } 76 | for i := start; i < len(s.arr); i++ { 77 | s.out = append(s.out, s.arr[i]) 78 | s.helper(target-s.arr[i], i) 79 | s.out = s.out[:len(s.out)-1] 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /go/leetcode/40.组合总和-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=40 lang=golang 3 | * 4 | * [40] 组合总和 II 5 | * 6 | * https://leetcode-cn.com/problems/combination-sum-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (55.85%) 10 | * Likes: 109 11 | * Dislikes: 0 12 | * Total Accepted: 15.1K 13 | * Total Submissions: 27K 14 | * Testcase Example: '[10,1,2,7,6,1,5]\n8' 15 | * 16 | * 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 17 | * 18 | * candidates 中的每个数字在每个组合中只能使用一次。 19 | * 20 | * 说明: 21 | * 22 | * 23 | * 所有数字(包括目标数)都是正整数。 24 | * 解集不能包含重复的组合。 25 | * 26 | * 27 | * 示例 1: 28 | * 29 | * 输入: candidates = [10,1,2,7,6,1,5], target = 8, 30 | * 所求解集为: 31 | * [ 32 | * ⁠ [1, 7], 33 | * ⁠ [1, 2, 5], 34 | * ⁠ [2, 6], 35 | * ⁠ [1, 1, 6] 36 | * ] 37 | * 38 | * 39 | * 示例 2: 40 | * 41 | * 输入: candidates = [2,5,2,1,2], target = 5, 42 | * 所求解集为: 43 | * [ 44 | * [1,2,2], 45 | * [5] 46 | * ] 47 | * 48 | */ 49 | 50 | import ( 51 | "sort" 52 | ) 53 | 54 | type solution struct { 55 | out []int 56 | res [][]int 57 | } 58 | 59 | func (s *solution) helper(arr []int, target int, start int) { 60 | if target < 0 { 61 | return 62 | } 63 | if target == 0 { 64 | s.res = append(s.res, append([]int{}, (s.out)...)) // 复制值 65 | return 66 | } 67 | for i := start; i < len(arr); i++ { 68 | if i > start && arr[i] == arr[i-1] { 69 | continue 70 | } 71 | s.out = append(s.out, arr[i]) 72 | s.helper(arr, target-arr[i], i+1) 73 | s.out = s.out[:len(s.out)-1] 74 | } 75 | } 76 | 77 | func combinationSum2(candidates []int, target int) [][]int { 78 | sort.Ints(candidates) 79 | s := &solution{ 80 | out: []int{}, 81 | res: [][]int{}, 82 | } 83 | s.helper(candidates, target, 0) 84 | return s.res 85 | } 86 | 87 | -------------------------------------------------------------------------------- /go/leetcode/41.缺失的第一个正数.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=41 lang=golang 3 | * 4 | * [41] 缺失的第一个正数 5 | * 6 | * https://leetcode-cn.com/problems/first-missing-positive/description/ 7 | * 8 | * algorithms 9 | * Hard (36.29%) 10 | * Likes: 269 11 | * Dislikes: 0 12 | * Total Accepted: 23.4K 13 | * Total Submissions: 64.1K 14 | * Testcase Example: '[1,2,0]' 15 | * 16 | * 给定一个未排序的整数数组,找出其中没有出现的最小的正整数。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: [1,2,0] 21 | * 输出: 3 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: [3,4,-1,1] 27 | * 输出: 2 28 | * 29 | * 30 | * 示例 3: 31 | * 32 | * 输入: [7,8,9,11,12] 33 | * 输出: 1 34 | * 35 | * 36 | * 说明: 37 | * 38 | * 你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。 39 | * 40 | */ 41 | 42 | // 原地交换排序,两次遍历 43 | // 交换后的数组要符合[1,2,3,4... ]的规则,第一个不符合这样规则的位置,就是结果 44 | func firstMissingPositive(nums []int) int { 45 | size := len(nums) 46 | for i := 0; i < size; i++ { 47 | for nums[i] > 0 && nums[i] < size && nums[i] != nums[nums[i]-1] { // 1应该在0位 48 | nums[i], nums[nums[i]-1] = nums[nums[i]-1], nums[i] 49 | } 50 | } 51 | for i := 0; i < size; i++ { 52 | if nums[i] != i+1 { 53 | return i + 1 54 | } 55 | } 56 | return size + 1 57 | } 58 | 59 | -------------------------------------------------------------------------------- /go/leetcode/42.接雨水.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=42 lang=golang 3 | * 4 | * [42] 接雨水 5 | * 6 | * https://leetcode-cn.com/problems/trapping-rain-water/description/ 7 | * 8 | * algorithms 9 | * Hard (46.20%) 10 | * Likes: 565 11 | * Dislikes: 0 12 | * Total Accepted: 25.6K 13 | * Total Submissions: 55.5K 14 | * Testcase Example: '[0,1,0,2,1,0,1,3,2,1,2,1]' 15 | * 16 | * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 17 | * 18 | * 19 | * 20 | * 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 21 | * Marcos 贡献此图。 22 | * 23 | * 示例: 24 | * 25 | * 输入: [0,1,0,2,1,0,1,3,2,1,2,1] 26 | * 输出: 6 27 | * 28 | */ 29 | 30 | // 双指针解法,与另外一道接雨水类似 31 | // 先判断左右两侧大小,从低的一侧开始走,如果发现有更低的,那么必然可以装起来,因为另一侧有更高的边界 32 | func trap(height []int) int { 33 | res := 0 34 | i := 0 35 | j := len(height) - 1 36 | leftMax := 0 37 | rightMax := 0 38 | for i < j { 39 | if height[i] < height[j] { 40 | if height[i] >= leftMax { 41 | leftMax = height[i] 42 | } else { 43 | res += leftMax - height[i] 44 | } 45 | i++ 46 | } else { 47 | if height[j] >= rightMax { 48 | rightMax = height[j] 49 | } else { 50 | res += rightMax - height[j] 51 | } 52 | j-- 53 | } 54 | } 55 | return res 56 | } 57 | 58 | -------------------------------------------------------------------------------- /go/leetcode/43.字符串相乘.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=43 lang=golang 3 | * 4 | * [43] 字符串相乘 5 | * 6 | * https://leetcode-cn.com/problems/multiply-strings/description/ 7 | * 8 | * algorithms 9 | * Medium (40.37%) 10 | * Likes: 214 11 | * Dislikes: 0 12 | * Total Accepted: 29K 13 | * Total Submissions: 71.5K 14 | * Testcase Example: '"2"\n"3"' 15 | * 16 | * 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: num1 = "2", num2 = "3" 21 | * 输出: "6" 22 | * 23 | * 示例 2: 24 | * 25 | * 输入: num1 = "123", num2 = "456" 26 | * 输出: "56088" 27 | * 28 | * 说明: 29 | * 30 | * 31 | * num1 和 num2 的长度小于110。 32 | * num1 和 num2 只包含数字 0-9。 33 | * num1 和 num2 均不以零开头,除非是数字 0 本身。 34 | * 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。 35 | * 36 | * 37 | */ 38 | 39 | // @lc code=start 40 | import ( 41 | "strconv" 42 | ) 43 | 44 | const zero byte = '0' 45 | func multiply(num1 string, num2 string) string { 46 | if num1 == "0" || num2 == "0" { 47 | return "0" 48 | } 49 | m := len(num1) 50 | n := len(num2) 51 | digit := make([]int, m+n) 52 | for i := m - 1; i >= 0; i-- { 53 | for j := n - 1; j >= 0; j-- { // 数据的低位存在数组的高位 54 | tmp := int(num1[i] - zero) * int(num2[j] - zero) + digit[i+j+1] // 从0开始所以+1 55 | digit[i+j+1] = tmp % 10 // 数组的高位存数据的低位 56 | digit[i+j] += tmp / 10 // 数组的低位存数据的高位 57 | } 58 | } 59 | k := 0 60 | for ; k < len(digit) && digit[k] == 0; k++ { 61 | // 清理高位的0 62 | } 63 | res := "" 64 | for ; k < len(digit); k++ { 65 | res += strconv.Itoa(digit[k]) 66 | } 67 | return res 68 | } 69 | // @lc code=end 70 | -------------------------------------------------------------------------------- /go/leetcode/445.两数相加-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=445 lang=golang 3 | * 4 | * [445] 两数相加 II 5 | * 6 | * https://leetcode-cn.com/problems/add-two-numbers-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (48.63%) 10 | * Likes: 63 11 | * Dislikes: 0 12 | * Total Accepted: 4.2K 13 | * Total Submissions: 8.5K 14 | * Testcase Example: '[7,2,4,3]\n[5,6,4]' 15 | * 16 | * 给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。 17 | * 18 | * 19 | * 20 | * 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 21 | * 22 | * 进阶: 23 | * 24 | * 如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。 25 | * 26 | * 示例: 27 | * 28 | * 29 | * 输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 30 | * 输出: 7 -> 8 -> 0 -> 7 31 | * 32 | * 33 | */ 34 | /** 35 | * Definition for singly-linked list. 36 | * type ListNode struct { 37 | * Val int 38 | * Next *ListNode 39 | * } 40 | */ 41 | func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { 42 | arr1 := []*ListNode{} 43 | arr2 := []*ListNode{} 44 | for c := l1; c != nil; c = c.Next { 45 | arr1 = append(arr1, c) 46 | } 47 | for c := l2; c != nil; c = c.Next { 48 | arr2 = append(arr2, c) 49 | } 50 | len1 := len(arr1) 51 | len2 := len(arr2) 52 | dummy := &ListNode{} 53 | i := 0 54 | n := 0 // 进位数 55 | for i < len1 || i < len2 { 56 | s := n 57 | if i < len1 { 58 | s += arr1[len1-1-i].Val 59 | } 60 | if i < len2 { 61 | s += arr2[len2-1-i].Val 62 | } 63 | n = s / 10 64 | c := &ListNode{} 65 | c.Val = s % 10 66 | c.Next = dummy.Next 67 | dummy.Next = c 68 | i++ 69 | } 70 | if n != 0 { 71 | c := &ListNode{} 72 | c.Val = n % 10 73 | c.Next = dummy.Next 74 | dummy.Next = c 75 | } 76 | return dummy.Next 77 | } 78 | 79 | -------------------------------------------------------------------------------- /go/leetcode/45.跳跃游戏 II.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=45 lang=golang 3 | * 4 | * [45] 跳跃游戏 II 5 | * 6 | * https://leetcode-cn.com/problems/jump-game-ii/description/ 7 | * 8 | * algorithms 9 | * Hard (31.41%) 10 | * Likes: 258 11 | * Dislikes: 0 12 | * Total Accepted: 17.9K 13 | * Total Submissions: 56.9K 14 | * Testcase Example: '[2,3,1,1,4]' 15 | * 16 | * 给定一个非负整数数组,你最初位于数组的第一个位置。 17 | * 18 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 19 | * 20 | * 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 21 | * 22 | * 示例: 23 | * 24 | * 输入: [2,3,1,1,4] 25 | * 输出: 2 26 | * 解释: 跳到最后一个位置的最小跳跃数是 2。 27 | * 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 28 | * 29 | * 30 | * 说明: 31 | * 32 | * 假设你总是可以到达数组的最后一个位置。 33 | * 34 | */ 35 | 36 | // 滑动窗口,在每一跳的可选范围里面选包括下一步能走的最远距离 37 | // [5,1,7,9,3,4,1,2,1,1,1,3] 38 | // 第一步在[1,5]之间选,尽量在可选区间的右侧,且下一跳范围更大,也就是i+nums[i]最大 39 | // 第二步更新左右边界 40 | func jump(nums []int) int { 41 | step, n := 0, len(nums) - 1 42 | left, right := 0, 0 43 | for right < n { 44 | max := right // 尽可能选右边 45 | for i := left; i <= right; i++ { // 注意=号,保证可以启动 46 | if i+nums[i] > max { 47 | max = i+nums[i] 48 | } 49 | } 50 | left = right+1 // right看过了,下一个 51 | right = max 52 | step++ 53 | } 54 | return step 55 | } 56 | 57 | -------------------------------------------------------------------------------- /go/leetcode/47.全排列 II.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=47 lang=golang 3 | * 4 | * [47] 全排列 II 5 | * 6 | * https://leetcode-cn.com/problems/permutations-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (53.86%) 10 | * Likes: 164 11 | * Dislikes: 0 12 | * Total Accepted: 23.5K 13 | * Total Submissions: 43.3K 14 | * Testcase Example: '[1,1,2]' 15 | * 16 | * 给定一个可包含重复数字的序列,返回所有不重复的全排列。 17 | * 18 | * 示例: 19 | * 20 | * 输入: [1,1,2] 21 | * 输出: 22 | * [ 23 | * ⁠ [1,1,2], 24 | * ⁠ [1,2,1], 25 | * ⁠ [2,1,1] 26 | * ] 27 | * 28 | */ 29 | 30 | // @lc code=start 31 | import ( 32 | "sort" 33 | ) 34 | 35 | func permuteUnique(nums []int) [][]int { 36 | sort.Ints(nums) 37 | visited := make([]bool, len(nums)) 38 | out := []int{} 39 | res := [][]int{} 40 | permuteDFS(&nums, &visited, &out, &res) 41 | return res 42 | } 43 | 44 | // 深度优先递归,通过访问标记数组去重 45 | func permuteDFS(nums *[]int, visited *[]bool, out *[]int, res *[][]int) { 46 | if len(*out) == len(*nums) { 47 | *res = append(*res, append([]int{}, (*out)...)) // 复制值 48 | return 49 | } 50 | for i := 0; i < len(*nums); i++ { 51 | if (*visited)[i] { 52 | continue 53 | } 54 | if (i > 0 && (*nums)[i] == (*nums)[i-1] && !(*visited)[i-1]) { 55 | // 用多叉树来描述解的空间: 56 | // a0 a1(跳过) b 57 | // a1 b a0 a1(跳过) 58 | // b a1 a1 59 | // 横向第二个相同元素直接跳过,因为前面已经走过一次了,或者说a0/a1这两颗子树完全一样 60 | continue 61 | } 62 | (*visited)[i] = true 63 | *out = append(*out, (*nums)[i]) 64 | permuteDFS(nums, visited, out, res) 65 | *out = (*out)[:len(*out)-1] 66 | (*visited)[i] = false 67 | } 68 | } 69 | // @lc code=end -------------------------------------------------------------------------------- /go/leetcode/48.旋转图像.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=48 lang=golang 3 | * 4 | * [48] 旋转图像 5 | * 6 | * https://leetcode-cn.com/problems/rotate-image/description/ 7 | * 8 | * algorithms 9 | * Medium (64.05%) 10 | * Likes: 291 11 | * Dislikes: 0 12 | * Total Accepted: 36.9K 13 | * Total Submissions: 57K 14 | * Testcase Example: '[[1,2,3],[4,5,6],[7,8,9]]' 15 | * 16 | * 给定一个 n × n 的二维矩阵表示一个图像。 17 | * 18 | * 将图像顺时针旋转 90 度。 19 | * 20 | * 说明: 21 | * 22 | * 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。 23 | * 24 | * 示例 1: 25 | * 26 | * 给定 matrix = 27 | * [ 28 | * ⁠ [1,2,3], 29 | * ⁠ [4,5,6], 30 | * ⁠ [7,8,9] 31 | * ], 32 | * 33 | * 原地旋转输入矩阵,使其变为: 34 | * [ 35 | * ⁠ [7,4,1], 36 | * ⁠ [8,5,2], 37 | * ⁠ [9,6,3] 38 | * ] 39 | * 40 | * 41 | * 示例 2: 42 | * 43 | * 给定 matrix = 44 | * [ 45 | * ⁠ [ 5, 1, 9,11], 46 | * ⁠ [ 2, 4, 8,10], 47 | * ⁠ [13, 3, 6, 7], 48 | * ⁠ [15,14,12,16] 49 | * ], 50 | * 51 | * 原地旋转输入矩阵,使其变为: 52 | * [ 53 | * ⁠ [15,13, 2, 5], 54 | * ⁠ [14, 3, 4, 1], 55 | * ⁠ [12, 6, 8, 9], 56 | * ⁠ [16, 7,10,11] 57 | * ] 58 | * 59 | * 60 | */ 61 | // 从外圈开始一圈一圈地旋转, 每次将一个位置的4个点都旋转好,只需要一个额外空间做中介 62 | // 00>03>33>30>00; 01>13>32>30>01...x1+y2=n && x2=y1 63 | // 11>12>22>21>11 64 | func rotate(matrix [][]int) { 65 | n := len(matrix) 66 | for i := 0; i < n/2; i++ { // 斜线,奇数不转中心,所以小于不等于 67 | for j := i; j < n-i-1; j++ { // 旋转圈上的一边,注意去掉最后一个 68 | // 一圈有4个位置 69 | tmp := matrix[i][j] 70 | matrix[i][j] = matrix[n - 1 - j][i] 71 | matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j] 72 | matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i] 73 | matrix[j][n - 1 - i] = tmp 74 | } 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /go/leetcode/49.字母异位词分组.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=49 lang=golang 3 | * 4 | * [49] 字母异位词分组 5 | * 6 | * https://leetcode-cn.com/problems/group-anagrams/description/ 7 | * 8 | * algorithms 9 | * Medium (58.35%) 10 | * Likes: 192 11 | * Dislikes: 0 12 | * Total Accepted: 31.3K 13 | * Total Submissions: 53.4K 14 | * Testcase Example: '["eat","tea","tan","ate","nat","bat"]' 15 | * 16 | * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 17 | * 18 | * 示例: 19 | * 20 | * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], 21 | * 输出: 22 | * [ 23 | * ⁠ ["ate","eat","tea"], 24 | * ⁠ ["nat","tan"], 25 | * ⁠ ["bat"] 26 | * ] 27 | * 28 | * 说明: 29 | * 30 | * 31 | * 所有输入均为小写字母。 32 | * 不考虑答案输出的顺序。 33 | * 34 | * 35 | */ 36 | 37 | import ( 38 | "sort" 39 | ) 40 | 41 | // @lc code=start 42 | func groupAnagrams(strs []string) [][]string { 43 | cm := map[[26]int]int{} 44 | ret := [][]string{} 45 | var a rune = 'a' 46 | for _, str := range strs { 47 | ca := [26]int{} 48 | for _, c := range str { 49 | ca[c-a] += 1 50 | } 51 | if i, ok := cm[ca]; ok { 52 | ret[i] = append(ret[i], str) 53 | } else { 54 | ret = append(ret, []string{str}) 55 | cm[ca] = len(ret) - 1 56 | } 57 | } 58 | return ret 59 | } 60 | // @lc code=end 61 | 62 | -------------------------------------------------------------------------------- /go/leetcode/5.最长回文子串.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=5 lang=golang 3 | * 4 | * [5] 最长回文子串 5 | * 6 | * https://leetcode-cn.com/problems/longest-palindromic-substring/description/ 7 | * 8 | * algorithms 9 | * Medium (24.38%) 10 | * Total Accepted: 38.2K 11 | * Total Submissions: 155.7K 12 | * Testcase Example: '"babad"' 13 | * 14 | * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 15 | * 16 | * 示例 1: 17 | * 18 | * 输入: "babad" 19 | * 输出: "bab" 20 | * 注意: "aba" 也是一个有效答案。 21 | * 22 | * 23 | * 示例 2: 24 | * 25 | * 输入: "cbbd" 26 | * 输出: "bb" 27 | * 28 | * 29 | */ 30 | func findPalindrome(s string, left int, right int) string { 31 | j := left 32 | k := right 33 | l := len(s) 34 | ret := s[j : k+1] 35 | for { 36 | j-- 37 | k++ 38 | if j < 0 || k > l-1 { 39 | break 40 | } 41 | if s[j] != s[k] { 42 | break 43 | } 44 | ret = s[j : k+1] 45 | } 46 | return string(ret) 47 | } 48 | 49 | func longestPalindrome(s string) string { 50 | l := len(s) 51 | if l < 2 { 52 | return s 53 | } 54 | target := s[:1] 55 | for i := 0; i < l-1; i++ { 56 | if s[i] == s[i+1] { 57 | p := findPalindrome(s, i, i+1) 58 | if len(target) < len(p) { 59 | target = p 60 | } 61 | } 62 | if i-1 >= 0 && i+1 < l && s[i-1] == s[i+1] { 63 | p := findPalindrome(s, i-1, i+1) 64 | if len(target) < len(p) { 65 | target = p 66 | } 67 | } 68 | } 69 | return target 70 | } 71 | 72 | -------------------------------------------------------------------------------- /go/leetcode/50.Pow(x, n).go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=50 lang=golang 3 | * 4 | * [50] Pow(x, n) 5 | * 6 | * https://leetcode-cn.com/problems/powx-n/description/ 7 | * 8 | * algorithms 9 | * Medium (33.20%) 10 | * Likes: 173 11 | * Dislikes: 0 12 | * Total Accepted: 32K 13 | * Total Submissions: 96.4K 14 | * Testcase Example: '2.00000\n10' 15 | * 16 | * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: 2.00000, 10 21 | * 输出: 1024.00000 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: 2.10000, 3 27 | * 输出: 9.26100 28 | * 29 | * 30 | * 示例 3: 31 | * 32 | * 输入: 2.00000, -2 33 | * 输出: 0.25000 34 | * 解释: 2^-2 = 1/2^2 = 1/4 = 0.25 35 | * 36 | * 说明: 37 | * 38 | * 39 | * -100.0 < x < 100.0 40 | * n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] 。 41 | * 42 | * 43 | */ 44 | func myPow(x float64, n int) float64 { 45 | // 3 ^ 5 = 3 * 3^2 46 | res := float64(1.0) 47 | for i := n; i != 0; i /= 2 { 48 | if i % 2 != 0 { 49 | res *= x 50 | } 51 | x *= x 52 | } 53 | if n < 0 { 54 | return 1 / res 55 | } 56 | return res 57 | } 58 | 59 | -------------------------------------------------------------------------------- /go/leetcode/53.最大子序和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=53 lang=golang 3 | * 4 | * [53] 最大子序和 5 | */ 6 | 7 | import ( 8 | "math" 9 | ) 10 | 11 | func maxSubArray(nums []int) int { 12 | if len(nums) == 0 { 13 | return 0 14 | } 15 | maxSum := math.MinInt32 16 | sum := 0 17 | for _, n := range nums { 18 | sum += n 19 | if sum > maxSum { 20 | maxSum = sum 21 | } 22 | if sum < 0 { 23 | sum = 0 24 | } 25 | } 26 | return maxSum 27 | } 28 | 29 | -------------------------------------------------------------------------------- /go/leetcode/55.跳跃游戏.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=55 lang=golang 3 | * 4 | * [55] 跳跃游戏 5 | * 6 | * https://leetcode-cn.com/problems/jump-game/description/ 7 | * 8 | * algorithms 9 | * Medium (36.07%) 10 | * Likes: 326 11 | * Dislikes: 0 12 | * Total Accepted: 34K 13 | * Total Submissions: 93.7K 14 | * Testcase Example: '[2,3,1,1,4]' 15 | * 16 | * 给定一个非负整数数组,你最初位于数组的第一个位置。 17 | * 18 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 19 | * 20 | * 判断你是否能够到达最后一个位置。 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: [2,3,1,1,4] 25 | * 输出: true 26 | * 解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。 27 | * 28 | * 29 | * 示例 2: 30 | * 31 | * 输入: [3,2,1,0,4] 32 | * 输出: false 33 | * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 34 | * 35 | * 36 | */ 37 | 38 | // 与45求最小步数类似,这里不需要关注left 39 | // 只需要关注当前i>=right,当i==right时,那就是说靠跳跃已经跳不过去i这个位置了 40 | func canJump(nums []int) bool { 41 | right := 0 42 | for i := 0; i < len(nums); i++ { 43 | if nums[i] + i > right { 44 | right = nums[i] + i 45 | } 46 | if right >= len(nums) - 1 { 47 | return true 48 | } 49 | if i >= right { 50 | return false 51 | } 52 | } 53 | return false 54 | } 55 | 56 | -------------------------------------------------------------------------------- /go/leetcode/56.合并区间.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=56 lang=golang 3 | * 4 | * [56] 合并区间 5 | * 6 | * https://leetcode-cn.com/problems/merge-intervals/description/ 7 | * 8 | * algorithms 9 | * Medium (38.17%) 10 | * Likes: 192 11 | * Dislikes: 0 12 | * Total Accepted: 30K 13 | * Total Submissions: 77.8K 14 | * Testcase Example: '[[1,3],[2,6],[8,10],[15,18]]' 15 | * 16 | * 给出一个区间的集合,请合并所有重叠的区间。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: [[1,3],[2,6],[8,10],[15,18]] 21 | * 输出: [[1,6],[8,10],[15,18]] 22 | * 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. 23 | * 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: [[1,4],[4,5]] 28 | * 输出: [[1,5]] 29 | * 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 30 | * 31 | */ 32 | 33 | import ( 34 | "sort" 35 | ) 36 | 37 | type SortArray [][]int 38 | 39 | func (a SortArray) Len() int { 40 | return len(a) 41 | } 42 | func (a SortArray) Swap(i, j int) { 43 | a[i], a[j] = a[j], a[i] 44 | } 45 | func (a SortArray) Less(i, j int) bool { 46 | return a[i][0] < a[j][0] 47 | } 48 | 49 | func merge(intervals [][]int) [][]int { 50 | sort.Sort(SortArray(intervals)) 51 | ret := [][]int{} 52 | tmp := []int{} 53 | for i := 0; i < len(intervals); i++ { 54 | if len(tmp) <= 0 { 55 | tmp = intervals[i] 56 | } 57 | if i >= len(intervals) - 1 { 58 | ret = append(ret, tmp) 59 | break 60 | } 61 | if tmp[1] >= intervals[i+1][0] { // 有重叠 62 | if tmp[1] < intervals[i+1][1] { 63 | tmp[1] = intervals[i+1][1] 64 | } 65 | } else { 66 | ret = append(ret, tmp) 67 | tmp = []int{} 68 | } 69 | } 70 | return ret 71 | } 72 | -------------------------------------------------------------------------------- /go/leetcode/58.最后一个单词的长度.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=58 lang=golang 3 | * 4 | * [58] 最后一个单词的长度 5 | */ 6 | import ( 7 | ) 8 | func lengthOfLastWord(s string) int { 9 | r := len(s) - 1 10 | res := 0 11 | for r >=0 && s[r] == " "[0] { 12 | r-- 13 | } 14 | for r >= 0 && s[r] != " "[0] { 15 | r-- 16 | res++ 17 | } 18 | return res 19 | } 20 | 21 | -------------------------------------------------------------------------------- /go/leetcode/59.螺旋矩阵-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=59 lang=golang 3 | * 4 | * [59] 螺旋矩阵 II 5 | * 6 | * https://leetcode-cn.com/problems/spiral-matrix-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (74.51%) 10 | * Likes: 120 11 | * Dislikes: 0 12 | * Total Accepted: 16.4K 13 | * Total Submissions: 21.9K 14 | * Testcase Example: '3' 15 | * 16 | * 给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。 17 | * 18 | * 示例: 19 | * 20 | * 输入: 3 21 | * 输出: 22 | * [ 23 | * ⁠[ 1, 2, 3 ], 24 | * ⁠[ 8, 9, 4 ], 25 | * ⁠[ 7, 6, 5 ] 26 | * ] 27 | * 28 | */ 29 | 30 | // package leetcode 31 | 32 | // @lc code=start 33 | func generateMatrix(n int) [][]int { 34 | res := make([][]int, n) 35 | for i := 0; i < n; i++ { 36 | res[i] = make([]int, n) 37 | } 38 | left, right, up, down := 0, n-1, 0, n-1 39 | i := 1 40 | for { 41 | for j := left; j <= right; j++ { 42 | res[up][j] = i 43 | i++ 44 | } 45 | up++ 46 | if up > down { 47 | break 48 | } 49 | for j := up; j <= down; j++ { 50 | res[j][right] = i 51 | i++ 52 | } 53 | right-- 54 | if left > right { 55 | break 56 | } 57 | for j := right; j >= left; j-- { 58 | res[down][j] = i 59 | i++ 60 | } 61 | down-- 62 | if up > down { 63 | break 64 | } 65 | for j := down; j >= up; j-- { 66 | res[j][left] = i 67 | i++ 68 | } 69 | left++ 70 | if left > right { 71 | break 72 | } 73 | } 74 | return res 75 | } 76 | 77 | // @lc code=end 78 | -------------------------------------------------------------------------------- /go/leetcode/60.第k个排列.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=60 lang=golang 3 | * 4 | * [60] 第k个排列 5 | * 6 | * https://leetcode-cn.com/problems/permutation-sequence/description/ 7 | * 8 | * algorithms 9 | * Medium (46.71%) 10 | * Likes: 123 11 | * Dislikes: 0 12 | * Total Accepted: 14.3K 13 | * Total Submissions: 30.4K 14 | * Testcase Example: '3\n3' 15 | * 16 | * 给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。 17 | * 18 | * 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: 19 | * 20 | * 21 | * "123" 22 | * "132" 23 | * "213" 24 | * "231" 25 | * "312" 26 | * "321" 27 | * 28 | * 29 | * 给定 n 和 k,返回第 k 个排列。 30 | * 31 | * 说明: 32 | * 33 | * 34 | * 给定 n 的范围是 [1, 9]。 35 | * 给定 k 的范围是[1,  n!]。 36 | * 37 | * 38 | * 示例 1: 39 | * 40 | * 输入: n = 3, k = 3 41 | * 输出: "213" 42 | * 43 | * 44 | * 示例 2: 45 | * 46 | * 输入: n = 4, k = 9 47 | * 输出: "2314" 48 | * 49 | * 50 | */ 51 | func getPermutation(n int, k int) string { 52 | // 1234 1243 1324 1342 1423 1432 53 | // 第n位固定、其他位的取值有(n-1)!种 54 | nums := []byte("123456789") 55 | c := make([]int, n) 56 | c[0] = 1 57 | // 预先算好阶乘 58 | for i := 1; i < n; i++ { 59 | c[i] = c[i-1] * i 60 | } 61 | ret := "" 62 | k-- // 序号从0开始 63 | for i := n-1; i >= 0; i-- { 64 | j := k / c[i] // 8/6 2/2 65 | ret += string(nums[j]) // 2 3 66 | if j + 1 < len(nums) { // 134 67 | nums = append(nums[:j], nums[j+1: ]...) 68 | } else { 69 | nums = nums[:j] 70 | } 71 | k %= c[i] // 2 72 | } 73 | return ret 74 | } 75 | 76 | -------------------------------------------------------------------------------- /go/leetcode/62.不同路径.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=62 lang=golang 3 | * 4 | * [62] 不同路径 5 | * 6 | * https://leetcode-cn.com/problems/unique-paths/description/ 7 | * 8 | * algorithms 9 | * Medium (55.98%) 10 | * Likes: 330 11 | * Dislikes: 0 12 | * Total Accepted: 41.8K 13 | * Total Submissions: 73.9K 14 | * Testcase Example: '3\n2' 15 | * 16 | * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 17 | * 18 | * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 19 | * 20 | * 问总共有多少条不同的路径? 21 | * 22 | * 23 | * 24 | * 例如,上图是一个7 x 3 的网格。有多少可能的路径? 25 | * 26 | * 说明:m 和 n 的值均不超过 100。 27 | * 28 | * 示例 1: 29 | * 30 | * 输入: m = 3, n = 2 31 | * 输出: 3 32 | * 解释: 33 | * 从左上角开始,总共有 3 条路径可以到达右下角。 34 | * 1. 向右 -> 向右 -> 向下 35 | * 2. 向右 -> 向下 -> 向右 36 | * 3. 向下 -> 向右 -> 向右 37 | * 38 | * 39 | * 示例 2: 40 | * 41 | * 输入: m = 7, n = 3 42 | * 输出: 28 43 | * 44 | */ 45 | func uniquePaths(m int, n int) int { 46 | if m <= 0 || n <= 0 { 47 | return 0 48 | } 49 | // paths[i][j] = paths[i-1][j] + paths[i][j-1] 50 | // 可换成1维度数组,只留下列,可以发现dp[j] = dp[j] + dp[j-1] 51 | // 1, 1, 1, 1, 1, 1, 1 52 | // 1, 2, 3, 4, 5, 6, 7 53 | // 1, 3, 6, 10,15,21,28 54 | dp := make([]int, n) 55 | for i := 0; i < n; i++ { // 第1行全是1 56 | dp[i] = 1 57 | } 58 | for i := 1; i < m; i++ { // 第1行全是1 59 | for j := 1; j < n; j++ { // 第一列全是1 60 | dp[j] = dp[j] + dp[j-1] 61 | } 62 | } 63 | return dp[n-1] 64 | } 65 | // 题目是一个组合问题,机器人必然要向下走m-1步,向右走n-1步 66 | // 换个角度看,机器人必定要走m+n-2步,其中选出m-1步往下走,这就变成了一个组合数问题 67 | // 假设m<=n,那么结果就是C(m-1,m+n-2),而C(m, n)=n!/(m!*(n-m)!) 68 | 69 | -------------------------------------------------------------------------------- /go/leetcode/63.不同路径-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=63 lang=golang 3 | * 4 | * [63] 不同路径 II 5 | * 6 | * https://leetcode-cn.com/problems/unique-paths-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (31.73%) 10 | * Likes: 167 11 | * Dislikes: 0 12 | * Total Accepted: 23.5K 13 | * Total Submissions: 73.8K 14 | * Testcase Example: '[[0,0,0],[0,1,0],[0,0,0]]' 15 | * 16 | * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 17 | * 18 | * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 19 | * 20 | * 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? 21 | * 22 | * 23 | * 24 | * 网格中的障碍物和空位置分别用 1 和 0 来表示。 25 | * 26 | * 说明:m 和 n 的值均不超过 100。 27 | * 28 | * 示例 1: 29 | * 30 | * 输入: 31 | * [ 32 | * [0,0,0], 33 | * [0,1,0], 34 | * [0,0,0] 35 | * ] 36 | * 输出: 2 37 | * 解释: 38 | * 3x3 网格的正中间有一个障碍物。 39 | * 从左上角到右下角一共有 2 条不同的路径: 40 | * 1. 向右 -> 向右 -> 向下 -> 向下 41 | * 2. 向下 -> 向下 -> 向右 -> 向右 42 | * 43 | * 44 | */ 45 | 46 | // @lc code=start 47 | func uniquePathsWithObstacles(obstacleGrid [][]int) int { 48 | m := len(obstacleGrid) 49 | if m <= 0 { 50 | return 0 51 | } 52 | n := len(obstacleGrid[0]) 53 | if n <= 0 { 54 | return 0 55 | } 56 | if obstacleGrid[m-1][n-1] == 1 { 57 | return 0 58 | } 59 | // paths[i][j] = paths[i-1][j] + paths[i][j-1] 60 | // 可换成1维度数组,只留下列,可以发现dp[j] = dp[j] + dp[j-1] 61 | // 1, 1, 1, 1, 1, 1, 1 62 | // 1, 2, 3, 4, 5, 6, 7 63 | // 1, 3, 6, 10,15,21,28 64 | dp := make([]int, n) 65 | dp[0] = 1 // 第一列为1 66 | for i := 0; i < m; i++ { 67 | for j := 0; j < n; j++ { // 第一列除了置0,其他都不走状态转移方程 68 | if obstacleGrid[i][j] == 1 { 69 | dp[j] = 0 70 | } else if j > 0 { 71 | dp[j] = dp[j] + dp[j-1] 72 | } 73 | } 74 | } 75 | return dp[n-1] 76 | } 77 | // @lc code=end 78 | 79 | -------------------------------------------------------------------------------- /go/leetcode/64.最小路径和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=64 lang=golang 3 | * 4 | * [64] 最小路径和 5 | * 6 | * https://leetcode-cn.com/problems/minimum-path-sum/description/ 7 | * 8 | * algorithms 9 | * Medium (62.26%) 10 | * Likes: 285 11 | * Dislikes: 0 12 | * Total Accepted: 33.3K 13 | * Total Submissions: 53.4K 14 | * Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' 15 | * 16 | * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 17 | * 18 | * 说明:每次只能向下或者向右移动一步。 19 | * 20 | * 示例: 21 | * 22 | * 输入: 23 | * [ 24 | * [1,3,1], 25 | * ⁠ [1,5,1], 26 | * ⁠ [4,2,1] 27 | * ] 28 | * 输出: 7 29 | * 解释: 因为路径 1→3→1→1→1 的总和最小。 30 | * 31 | * 32 | */ 33 | 34 | // @lc code=start 35 | func minPathSum(grid [][]int) int { 36 | //状态转移方程: paths[i][j] = grid[i][j] + min(paths[i-1][j], paths[i][j-1]) 37 | m := len(grid) 38 | if m <= 0 { 39 | return 0 40 | } 41 | n := len(grid[0]) 42 | if n <= 0 { 43 | return 0 44 | } 45 | dp := make([][]int, m) 46 | dp[0] = make([]int, n) 47 | dp[0][0] = grid[0][0] 48 | for i := 1; i < n; i++ { // 第1行只能累加 49 | dp[0][i] = dp[0][i-1] + grid[0][i] 50 | } 51 | for i := 1; i < m; i++ { // 第1列只能累加 52 | dp[i] = make([]int, n) // 初始化行 53 | dp[i][0] = dp[i-1][0] + grid[i][0] 54 | } 55 | for i := 1; i < m; i++ { 56 | for j := 1; j < n; j++ { 57 | if dp[i-1][j] < dp[i][j-1] { 58 | dp[i][j] = grid[i][j] + dp[i-1][j] 59 | } else { 60 | dp[i][j] = grid[i][j] + dp[i][j-1] 61 | } 62 | } 63 | } 64 | return dp[m-1][n-1] 65 | } 66 | 67 | // @lc code=end 68 | -------------------------------------------------------------------------------- /go/leetcode/66.加一.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=66 lang=golang 3 | * 4 | * [66] 加一 5 | */ 6 | func plusOne(digits []int) []int { 7 | n := 1 8 | for i := len(digits) - 1; i >= 0; i-- { 9 | s := digits[i] + n 10 | digits[i] = s % 10 11 | n = s / 10 12 | } 13 | ret := []int{} 14 | if n > 0 { 15 | ret = append(ret, n) 16 | } 17 | ret = append(ret, digits...) 18 | return ret 19 | } 20 | 21 | -------------------------------------------------------------------------------- /go/leetcode/67.二进制求和.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=67 lang=golang 3 | * 4 | * [67] 二进制求和 5 | * 6 | * https://leetcode-cn.com/problems/add-binary/description/ 7 | * 8 | * algorithms 9 | * Easy (49.08%) 10 | * Likes: 207 11 | * Dislikes: 0 12 | * Total Accepted: 28.2K 13 | * Total Submissions: 57.5K 14 | * Testcase Example: '"11"\n"1"' 15 | * 16 | * 给定两个二进制字符串,返回他们的和(用二进制表示)。 17 | * 18 | * 输入为非空字符串且只包含数字 1 和 0。 19 | * 20 | * 示例 1: 21 | * 22 | * 输入: a = "11", b = "1" 23 | * 输出: "100" 24 | * 25 | * 示例 2: 26 | * 27 | * 输入: a = "1010", b = "1011" 28 | * 输出: "10101" 29 | * 30 | */ 31 | 32 | // 注意进位 33 | // package leetcode 34 | 35 | // @lc code=start 36 | func addBinary(a string, b string) string { 37 | ret := "" 38 | carry := 0 39 | byteA := []byte(a) 40 | byteB := []byte(b) 41 | m := len(a) - 1 42 | n := len(b) - 1 43 | var zero byte = '0' 44 | for m >= 0 || n >= 0 { 45 | ca := 0 46 | if m >= 0 { 47 | ca = int(byteA[m] - zero) 48 | m-- 49 | } 50 | cb := 0 51 | if n >= 0 { 52 | cb = int(byteB[n] - zero) 53 | n-- 54 | } 55 | sum := ca + cb + carry 56 | ret = string(zero+byte(sum%2)) + ret 57 | carry = sum / 2 58 | } 59 | if carry > 0 { 60 | ret = "1" + ret 61 | } 62 | return ret 63 | } 64 | 65 | // @lc code=end 66 | -------------------------------------------------------------------------------- /go/leetcode/69.x 的平方根.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=69 lang=golang 3 | * 4 | * [69] x 的平方根 5 | * 6 | * https://leetcode-cn.com/problems/sqrtx/description/ 7 | * 8 | * algorithms 9 | * Easy (36.15%) 10 | * Likes: 176 11 | * Dislikes: 0 12 | * Total Accepted: 40.1K 13 | * Total Submissions: 111K 14 | * Testcase Example: '4' 15 | * 16 | * 实现 int sqrt(int x) 函数。 17 | * 18 | * 计算并返回 x 的平方根,其中 x 是非负整数。 19 | * 20 | * 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: 4 25 | * 输出: 2 26 | * 27 | * 28 | * 示例 2: 29 | * 30 | * 输入: 8 31 | * 输出: 2 32 | * 说明: 8 的平方根是 2.82842..., 33 | * 由于返回类型是整数,小数部分将被舍去。 34 | * 35 | * 36 | */ 37 | 38 | import ( 39 | "math" 40 | ) 41 | // 牛顿迭代法,x1=(x0+n/x0)/2 42 | func mySqrt(x int) int { 43 | if x <= 1 { 44 | return x 45 | } 46 | var res float64 = 1 47 | var pre float64 = 0 48 | for math.Abs(res - pre) > 1e-6 { 49 | pre = res 50 | res = (res + float64(x) / res) / 2 51 | } 52 | return int(res) 53 | } 54 | 55 | -------------------------------------------------------------------------------- /go/leetcode/7.reverse-integer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=7 lang=golang 3 | * 4 | * [7] 整数反转 5 | * 6 | * https://leetcode-cn.com/problems/reverse-integer/description/ 7 | * 8 | * algorithms 9 | * Easy (31.16%) 10 | * Total Accepted: 75.3K 11 | * Total Submissions: 241.4K 12 | * Testcase Example: '123' 13 | * 14 | * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 15 | * 16 | * 示例 1: 17 | * 18 | * 输入: 123 19 | * 输出: 321 20 | * 21 | * 22 | * 示例 2: 23 | * 24 | * 输入: -123 25 | * 输出: -321 26 | * 27 | * 28 | * 示例 3: 29 | * 30 | * 输入: 120 31 | * 输出: 21 32 | * 33 | * 34 | * 注意: 35 | * 36 | * 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231,  231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 37 | * 38 | */ 39 | func reverse(x int) int { 40 | ret := 0 41 | int_max := 1<<31 - 1 // 2147483647 42 | int_min := ^int_max // -2147483648 43 | for true { 44 | if x == 0 { 45 | break 46 | } 47 | // 提前判断ret是否溢出时,注意x本身就在int范围内,只要保证后面+x%10不溢出就可以了 48 | // 如果最后一步ret=214748364,根据x范围那么最后一位只能是1,也就是x的第一位是1,x=1463847412,ret=2147483641,不会溢出 49 | if ret > int_max/10 || ret < int_min/10 { 50 | return 0 51 | } 52 | ret = ret*10 + x%10 53 | x /= 10 54 | } 55 | return ret 56 | } 57 | -------------------------------------------------------------------------------- /go/leetcode/70.爬楼梯.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=70 lang=golang 3 | * 4 | * [70] 爬楼梯 5 | * 6 | * https://leetcode-cn.com/problems/climbing-stairs/description/ 7 | * 8 | * algorithms 9 | * Easy (52.07%) 10 | * Likes: 1695 11 | * Dislikes: 0 12 | * Total Accepted: 462.3K 13 | * Total Submissions: 888K 14 | * Testcase Example: '2' 15 | * 16 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 17 | * 18 | * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 19 | * 20 | * 注意:给定 n 是一个正整数。 21 | * 22 | * 示例 1: 23 | * 24 | * 输入: 2 25 | * 输出: 2 26 | * 解释: 有两种方法可以爬到楼顶。 27 | * 1. 1 阶 + 1 阶 28 | * 2. 2 阶 29 | * 30 | * 示例 2: 31 | * 32 | * 输入: 3 33 | * 输出: 3 34 | * 解释: 有三种方法可以爬到楼顶。 35 | * 1. 1 阶 + 1 阶 + 1 阶 36 | * 2. 1 阶 + 2 阶 37 | * 3. 2 阶 + 1 阶 38 | * 39 | * 40 | */ 41 | 42 | // @lc code=start 43 | func climbStairs(n int) int { 44 | // 动态规划,最后一步要么走1阶,要么走2阶 45 | // f(n) = f(n-1) + f(n-2) 46 | // 推广到一次最多可走k阶,那 f(n) = sum(f(n-i)), 其中i属于[1,k] 47 | if n <= 2 { 48 | return n 49 | } 50 | // dp := make([]int, n) 51 | // dp[0] = 1 52 | // dp[1] = 2 53 | // for i := 2; i < n; i++ { 54 | // dp[i] = dp[i-1] + dp[i-2] 55 | // } 56 | // return dp[n-1] 57 | 58 | // 上面的空间复杂度是O(n),但每次只有两个变量,所以用两个变量来代替 59 | dp2 := 1 // n-2 60 | dp1 := 2 // n-1 61 | dpn := 0 62 | for i := 2; i < n; i++ { 63 | dpn = dp1 + dp2 64 | dp2 = dp1 65 | dp1 = dpn 66 | } 67 | return dpn 68 | } 69 | 70 | // @lc code=end 71 | 72 | -------------------------------------------------------------------------------- /go/leetcode/75.颜色分类.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=75 lang=golang 3 | * 4 | * [75] 颜色分类 5 | * 6 | * https://leetcode-cn.com/problems/sort-colors/description/ 7 | * 8 | * algorithms 9 | * Medium (54.31%) 10 | * Likes: 487 11 | * Dislikes: 0 12 | * Total Accepted: 93.7K 13 | * Total Submissions: 169.9K 14 | * Testcase Example: '[2,0,2,1,1,0]' 15 | * 16 | * 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 17 | * 18 | * 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 19 | * 20 | * 注意: 21 | * 不能使用代码库中的排序函数来解决这道题。 22 | * 23 | * 示例: 24 | * 25 | * 输入: [2,0,2,1,1,0] 26 | * 输出: [0,0,1,1,2,2] 27 | * 28 | * 进阶: 29 | * 30 | * 31 | * 一个直观的解决方案是使用计数排序的两趟扫描算法。 32 | * 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 33 | * 你能想出一个仅使用常数空间的一趟扫描算法吗? 34 | * 35 | * 36 | */ 37 | 38 | // @lc code=start 39 | // 3指针解法,left(不包含left)之前必然是0,left为1,cur(不含)之前必然是1 40 | // right(不含)之后必然是2 41 | func sortColors(nums []int) { 42 | if len(nums) <= 1 { 43 | return 44 | } 45 | left, cur, right := 0, 0, len(nums)-1 46 | for cur <= right { 47 | if nums[cur] == 0 { 48 | nums[left], nums[cur] = nums[cur], nums[left] 49 | left++ 50 | cur++ // cur必然是1,可以直接++ 51 | } else if nums[cur] == 2 { 52 | nums[cur], nums[right] = nums[right], nums[cur] 53 | right-- // right可能是0或者1 54 | } else { 55 | cur++ 56 | } 57 | } 58 | } 59 | // @lc code=end 60 | 61 | -------------------------------------------------------------------------------- /go/leetcode/77.组合.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=77 lang=golang 3 | * 4 | * [77] 组合 5 | * 6 | * https://leetcode-cn.com/problems/combinations/description/ 7 | * 8 | * algorithms 9 | * Medium (68.47%) 10 | * Likes: 125 11 | * Dislikes: 0 12 | * Total Accepted: 12.8K 13 | * Total Submissions: 18.6K 14 | * Testcase Example: '4\n2' 15 | * 16 | * 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 17 | * 18 | * 示例: 19 | * 20 | * 输入: n = 4, k = 2 21 | * 输出: 22 | * [ 23 | * ⁠ [2,4], 24 | * ⁠ [3,4], 25 | * ⁠ [2,3], 26 | * ⁠ [1,2], 27 | * ⁠ [1,3], 28 | * ⁠ [1,4], 29 | * ] 30 | * 31 | */ 32 | 33 | // @lc code=start 34 | func combine(n int, k int) [][]int { 35 | s := &solution{ 36 | out: []int{}, 37 | res: [][]int{}, 38 | } 39 | s.call(n, k) 40 | return s.res 41 | } 42 | 43 | type solution struct { 44 | out []int 45 | res [][]int 46 | } 47 | 48 | func (s *solution) call(n int, k int) { 49 | if k <= 0 { 50 | s.res = append(s.res, append([]int{}, s.out...)) 51 | return 52 | } 53 | for i := n; i >= k; i-- { 54 | s.out = append(s.out, i) 55 | s.call(i-1, k-1) 56 | s.out = s.out[:len(s.out)-1] 57 | } 58 | } 59 | 60 | // @lc code=end 61 | 62 | -------------------------------------------------------------------------------- /go/leetcode/78.子集.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=78 lang=golang 3 | * 4 | * [78] 子集 5 | */ 6 | 7 | // subsets 从空集开始,遍历时每次对结果集合内的每个结果继续叠加 8 | // func subsets(nums []int) [][]int { 9 | // ret := [][]int{} 10 | // ret = append(ret, []int{}) 11 | // for i := 0; i < len(nums); i++ { 12 | // for _, sub := range ret { 13 | // sub = append(sub, nums[i]) 14 | // tmp := append([]int{}, sub...) 15 | // ret = append(ret, tmp) 16 | // } 17 | // } 18 | // return ret 19 | // } 20 | 21 | // 用回溯法,组合模式来做 22 | func subsets(nums []int) [][]int { 23 | s := &solution{ 24 | res: [][]int{}, 25 | path: []int{}, 26 | } 27 | s.call(nums, 0) 28 | return s.res 29 | } 30 | 31 | type solution struct { 32 | path []int 33 | res [][]int 34 | } 35 | 36 | func (s *solution) call(nums []int, start int) { 37 | if start > len(nums) { 38 | return 39 | } 40 | 41 | s.res = append(s.res, append([]int{}, s.path...)) 42 | 43 | for i := start; i < len(nums); i++ { 44 | s.path = append(s.path, nums[i]) 45 | s.call(nums, i+1) 46 | s.path = s.path[:len(s.path)-1] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /go/leetcode/80.删除排序数组中的重复项-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=80 lang=golang 3 | * 4 | * [80] 删除排序数组中的重复项 II 5 | * 6 | * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (51.91%) 10 | * Likes: 147 11 | * Dislikes: 0 12 | * Total Accepted: 24.7K 13 | * Total Submissions: 46.7K 14 | * Testcase Example: '[1,1,1,2,2,3]' 15 | * 16 | * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。 17 | * 18 | * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 19 | * 20 | * 示例 1: 21 | * 22 | * 给定 nums = [1,1,1,2,2,3], 23 | * 24 | * 函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 25 | * 26 | * 你不需要考虑数组中超出新长度后面的元素。 27 | * 28 | * 示例 2: 29 | * 30 | * 给定 nums = [0,0,1,1,1,1,2,3,3], 31 | * 32 | * 函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 33 | * 34 | * 你不需要考虑数组中超出新长度后面的元素。 35 | * 36 | * 37 | * 说明: 38 | * 39 | * 为什么返回数值是整数,但输出的答案是数组呢? 40 | * 41 | * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 42 | * 43 | * 你可以想象内部操作如下: 44 | * 45 | * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 46 | * int len = removeDuplicates(nums); 47 | * 48 | * // 在函数里修改输入数组对于调用者是可见的。 49 | * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 50 | * for (int i = 0; i < len; i++) { 51 | * print(nums[i]); 52 | * } 53 | * 54 | */ 55 | 56 | // package leetcode 57 | // 数组本身是拍好序的,现在限制最多两个重复,那么直接比较i和i-2,可以用双指针来实现 58 | // @lc code=start 59 | func removeDuplicates(nums []int) int { 60 | // 直接对比i和i-2的大小,如果==,则需要删掉i 61 | i := 0 62 | for j := 0; j < len(nums); j++ { 63 | if i < 2 || nums[j] > nums[i-2] { 64 | nums[i] = nums[j] 65 | i++ 66 | } 67 | } 68 | return i 69 | } 70 | // @lc code=end 71 | 72 | -------------------------------------------------------------------------------- /go/leetcode/82.删除排序链表中的重复元素-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=82 lang=golang 3 | * 4 | * [82] 删除排序链表中的重复元素 II 5 | * 6 | * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (41.32%) 10 | * Likes: 109 11 | * Dislikes: 0 12 | * Total Accepted: 10.8K 13 | * Total Submissions: 26.2K 14 | * Testcase Example: '[1,2,3,3,4,4,5]' 15 | * 16 | * 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: 1->2->3->3->4->4->5 21 | * 输出: 1->2->5 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: 1->1->1->2->3 27 | * 输出: 2->3 28 | * 29 | */ 30 | /** 31 | * Definition for singly-linked list. 32 | * type ListNode struct { 33 | * Val int 34 | * Next *ListNode 35 | * } 36 | */ 37 | 38 | func deleteDuplicates(head *ListNode) *ListNode { 39 | dummy := &ListNode{} 40 | dummy.Next = head 41 | pre := dummy 42 | cur := dummy.Next 43 | n := 0 44 | for cur != nil { 45 | if cur.Next != nil && cur.Next.Val == pre.Next.Val { 46 | cur = cur.Next 47 | n++ 48 | continue 49 | } 50 | if n > 0 { 51 | pre.Next = cur.Next 52 | cur = cur.Next 53 | n = 0 54 | continue 55 | } 56 | pre = pre.Next 57 | cur = cur.Next 58 | } 59 | return dummy.Next 60 | } 61 | 62 | -------------------------------------------------------------------------------- /go/leetcode/83.删除排序链表中的重复元素.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=83 lang=golang 3 | * 4 | * [83] 删除排序链表中的重复元素 5 | * 6 | * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/description/ 7 | * 8 | * algorithms 9 | * Easy (45.95%) 10 | * Likes: 158 11 | * Dislikes: 0 12 | * Total Accepted: 28.6K 13 | * Total Submissions: 62.2K 14 | * Testcase Example: '[1,1,2]' 15 | * 16 | * 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 17 | * 18 | * 示例 1: 19 | * 20 | * 输入: 1->1->2 21 | * 输出: 1->2 22 | * 23 | * 24 | * 示例 2: 25 | * 26 | * 输入: 1->1->2->3->3 27 | * 输出: 1->2->3 28 | * 29 | */ 30 | /** 31 | * Definition for singly-linked list. 32 | * type ListNode struct { 33 | * Val int 34 | * Next *ListNode 35 | * } 36 | */ 37 | func deleteDuplicates(head *ListNode) *ListNode { 38 | dummy := &ListNode{} 39 | dummy.Next = head 40 | pre := dummy 41 | cur := dummy.Next 42 | n := 0 43 | for cur != nil { 44 | if cur.Next != nil && cur.Next.Val == pre.Next.Val { 45 | cur = cur.Next // 1>1 46 | n++ // 1 47 | continue 48 | } 49 | if n > 0 { // 1 50 | pre.Next = cur // p>1>2 51 | pre = pre.Next // 1 52 | cur = cur.Next // 2 53 | n = 0 54 | continue 55 | } 56 | pre = pre.Next 57 | cur = cur.Next 58 | continue 59 | } 60 | return dummy.Next 61 | } 62 | 63 | -------------------------------------------------------------------------------- /go/leetcode/86.分隔链表.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=86 lang=golang 3 | * 4 | * [86] 分隔链表 5 | * 6 | * https://leetcode-cn.com/problems/partition-list/description/ 7 | * 8 | * algorithms 9 | * Medium (49.13%) 10 | * Likes: 92 11 | * Dislikes: 0 12 | * Total Accepted: 8.7K 13 | * Total Submissions: 17.7K 14 | * Testcase Example: '[1,4,3,2,5,2]\n3' 15 | * 16 | * 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。 17 | * 18 | * 你应当保留两个分区中每个节点的初始相对位置。 19 | * 20 | * 示例: 21 | * 22 | * 输入: head = 1->4->3->2->5->2, x = 3 23 | * 输出: 1->2->2->4->3->5 24 | * 25 | * 26 | */ 27 | /** 28 | * Definition for singly-linked list. 29 | * type ListNode struct { 30 | * Val int 31 | * Next *ListNode 32 | * } 33 | */ 34 | // 也是快慢指针:找到>=x的点之后,比x小的点插入到慢指针之后 35 | // 1. has_div表示是否找到>=x的点 36 | // 2. pre指针表示可被插入的位置 37 | // 3. 小于x的点都保持在pre点之后,pre指针总是会移动,要么移动到下一个,要不就是移动到新插入点上 38 | func partition(head *ListNode, x int) *ListNode { 39 | dummy := &ListNode{} 40 | dummy.Next = head 41 | has_div := false 42 | pre := dummy 43 | cur := dummy 44 | for cur != nil && cur.Next != nil { 45 | next := cur.Next // 因为需要插入,所以取前指针比较合适 46 | if next.Val >= x { 47 | if !has_div { // 第一次,找到分隔点 48 | has_div = true 49 | } 50 | cur = next // 继续往下走 51 | continue 52 | } 53 | if has_div { // 有分隔点,那就插入到分隔点 54 | cur.Next = next.Next // 从当前位置断开 55 | next.Next = pre.Next // 后接pre后指针 56 | pre.Next = next // 插入到pre之后 57 | } 58 | pre = pre.Next // 移动pre 59 | cur = next // 移动cur 60 | } 61 | return dummy.Next 62 | } 63 | 64 | -------------------------------------------------------------------------------- /go/leetcode/88.合并两个有序数组.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=88 lang=golang 3 | * 4 | * [88] 合并两个有序数组 5 | * 6 | * https://leetcode-cn.com/problems/merge-sorted-array/description/ 7 | * 8 | * algorithms 9 | * Easy (44.46%) 10 | * Likes: 264 11 | * Dislikes: 0 12 | * Total Accepted: 52.3K 13 | * Total Submissions: 117.7K 14 | * Testcase Example: '[1,2,3,0,0,0]\n3\n[2,5,6]\n3' 15 | * 16 | * 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 17 | * 18 | * 说明: 19 | * 20 | * 21 | * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 22 | * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 23 | * 24 | * 25 | * 示例: 26 | * 27 | * 输入: 28 | * nums1 = [1,2,3,0,0,0], m = 3 29 | * nums2 = [2,5,6], n = 3 30 | * 31 | * 输出: [1,2,2,3,5,6] 32 | * 33 | */ 34 | 35 | // 先规划空间然后从后往前元素进去 36 | // package leetcode 37 | 38 | // @lc code=start 39 | func merge(nums1 []int, m int, nums2 []int, n int) { 40 | for m > 0 && n > 0 { 41 | if nums1[m-1] > nums2[n-1] { 42 | nums1[m+n-1] = nums1[m-1] 43 | m-- 44 | } else { 45 | nums1[m+n-1] = nums2[n-1] 46 | n-- 47 | } 48 | } 49 | for m > 0 { 50 | nums1[m+n-1] = nums1[m-1] 51 | m-- 52 | } 53 | for n > 0 { 54 | nums1[m+n-1] = nums2[n-1] 55 | n-- 56 | } 57 | } 58 | 59 | // @lc code=end 60 | -------------------------------------------------------------------------------- /go/leetcode/9.palindrome-number.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=9 lang=golang 3 | * 4 | * [9] 回文数 5 | * 6 | * https://leetcode-cn.com/problems/palindrome-number/description/ 7 | * 8 | * algorithms 9 | * Easy (55.78%) 10 | * Total Accepted: 65.5K 11 | * Total Submissions: 117.4K 12 | * Testcase Example: '121' 13 | * 14 | * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 15 | * 16 | * 示例 1: 17 | * 18 | * 输入: 121 19 | * 输出: true 20 | * 21 | * 22 | * 示例 2: 23 | * 24 | * 输入: -121 25 | * 输出: false 26 | * 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 27 | * 28 | * 29 | * 示例 3: 30 | * 31 | * 输入: 10 32 | * 输出: false 33 | * 解释: 从右向左读, 为 01 。因此它不是一个回文数。 34 | * 35 | * 36 | * 进阶: 37 | * 38 | * 你能不将整数转为字符串来解决这个问题吗? 39 | * 40 | */ 41 | func isPalindrome(x int) bool { 42 | if x < 0 { 43 | return false 44 | } 45 | if x == 0 { 46 | return true 47 | } 48 | if x%10 == 0 { 49 | return false 50 | } 51 | y := 0 52 | for true { 53 | y = y*10 + x%10 54 | x /= 10 55 | if y == x { 56 | return true 57 | } 58 | if y > x { 59 | break 60 | } 61 | } 62 | return y == x || y/10 == x 63 | } 64 | -------------------------------------------------------------------------------- /go/leetcode/90.子集-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=90 lang=golang 3 | * 4 | * [90] 子集 II 5 | */ 6 | 7 | import ( 8 | "sort" 9 | ) 10 | 11 | // subsetsWithDup 首先排序,然后存上一个数字和当次遍历前的结果集s,当发现已经和上个数字相同的时候,则只处理s以外的结果 12 | func subsetsWithDup(nums []int) [][]int { 13 | ret := [][]int{} 14 | ret = append(ret, []int{}) 15 | if len(nums) == 0 { 16 | return ret 17 | } 18 | sort.Ints(nums) 19 | last := nums[0] 20 | size := 1 21 | for i := 0; i < len(nums); i++ { 22 | if last != nums[i] { 23 | last = nums[i] 24 | size = len(ret) 25 | } 26 | newSize := len(ret) 27 | for j := newSize - size; j < newSize; j++ { 28 | sub := ret[j] 29 | sub = append(sub, nums[i]) 30 | tmp := append([]int{}, sub...) 31 | ret = append(ret, tmp) 32 | } 33 | } 34 | return ret 35 | } 36 | 37 | -------------------------------------------------------------------------------- /go/leetcode/92.反转链表-ii.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=92 lang=golang 3 | * 4 | * [92] 反转链表 II 5 | * 6 | * https://leetcode-cn.com/problems/reverse-linked-list-ii/description/ 7 | * 8 | * algorithms 9 | * Medium (44.01%) 10 | * Likes: 137 11 | * Dislikes: 0 12 | * Total Accepted: 11K 13 | * Total Submissions: 24.9K 14 | * Testcase Example: '[1,2,3,4,5]\n2\n4' 15 | * 16 | * 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 17 | * 18 | * 说明: 19 | * 1 ≤ m ≤ n ≤ 链表长度。 20 | * 21 | * 示例: 22 | * 23 | * 输入: 1->2->3->4->5->NULL, m = 2, n = 4 24 | * 输出: 1->4->3->2->5->NULL 25 | * 26 | */ 27 | /** 28 | * Definition for singly-linked list. 29 | * type ListNode struct { 30 | * Val int 31 | * Next *ListNode 32 | * } 33 | */ 34 | 35 | // h>1>2>3>4>5 36 | // h>1>3>2>4>5 37 | // h>1>4>3>2>5 38 | func reverseBetween(head *ListNode, m int, n int) *ListNode { 39 | dummy := &ListNode{} 40 | dummy.Next = head 41 | i := 1 42 | pre := dummy 43 | cur := dummy.Next 44 | for cur != nil && cur.Next != nil { 45 | if i >= m && i < n { // 向后调整,不需要i==n 46 | next := cur.Next 47 | cur.Next = next.Next 48 | next.Next = pre.Next 49 | pre.Next = next 50 | i++ 51 | continue 52 | } 53 | pre = pre.Next 54 | cur = cur.Next 55 | i++ 56 | } 57 | return dummy.Next 58 | } 59 | -------------------------------------------------------------------------------- /go/leetcode/96.不同的二叉搜索树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=96 lang=golang 3 | * 4 | * [96] 不同的二叉搜索树 5 | * 6 | * https://leetcode-cn.com/problems/unique-binary-search-trees/description/ 7 | * 8 | * algorithms 9 | * Medium (62.17%) 10 | * Likes: 261 11 | * Dislikes: 0 12 | * Total Accepted: 16.8K 13 | * Total Submissions: 27.1K 14 | * Testcase Example: '3' 15 | * 16 | * 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 17 | * 18 | * 示例: 19 | * 20 | * 输入: 3 21 | * 输出: 5 22 | * 解释: 23 | * 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 24 | * 25 | * ⁠ 1 3 3 2 1 26 | * ⁠ \ / / / \ \ 27 | * ⁠ 3 2 1 1 3 2 28 | * ⁠ / / \ \ 29 | * ⁠ 2 1 2 3 30 | * 31 | */ 32 | // 卡塔兰数 33 | func numTrees(n int) int { 34 | if n < 2 { 35 | return 1 36 | } 37 | if n == 2 { 38 | return 2 39 | } 40 | count := 0 41 | for i := 0; i < n; i++ { 42 | count += numTrees(i) * numTrees(n-i-1) 43 | } 44 | return count 45 | } 46 | 47 | -------------------------------------------------------------------------------- /go/leetcode/98.验证二叉搜索树.go: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=98 lang=golang 3 | * 4 | * [98] 验证二叉搜索树 5 | * 6 | * https://leetcode-cn.com/problems/validate-binary-search-tree/description/ 7 | * 8 | * algorithms 9 | * Medium (27.53%) 10 | * Likes: 291 11 | * Dislikes: 0 12 | * Total Accepted: 40.8K 13 | * Total Submissions: 147.4K 14 | * Testcase Example: '[2,1,3]' 15 | * 16 | * 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 17 | * 18 | * 假设一个二叉搜索树具有如下特征: 19 | * 20 | * 21 | * 节点的左子树只包含小于当前节点的数。 22 | * 节点的右子树只包含大于当前节点的数。 23 | * 所有左子树和右子树自身必须也是二叉搜索树。 24 | * 25 | * 26 | * 示例 1: 27 | * 28 | * 输入: 29 | * ⁠ 2 30 | * ⁠ / \ 31 | * ⁠ 1 3 32 | * 输出: true 33 | * 34 | * 35 | * 示例 2: 36 | * 37 | * 输入: 38 | * ⁠ 5 39 | * ⁠ / \ 40 | * ⁠ 1 4 41 | * / \ 42 | * 3 6 43 | * 输出: false 44 | * 解释: 输入为: [5,1,4,null,null,3,6]。 45 | * 根节点的值为 5 ,但是其右子节点值为 4 。 46 | * 47 | * 48 | */ 49 | 50 | // @lc code=start 51 | /** 52 | * Definition for a binary tree node. 53 | * type TreeNode struct { 54 | * Val int 55 | * Left *TreeNode 56 | * Right *TreeNode 57 | * } 58 | */ 59 | func isValidBST(root *TreeNode) bool { 60 | var INT_MAX = int(^uint(0) >> 1) 61 | var INT_MIN = ^INT_MAX 62 | return helper(root, INT_MIN, INT_MAX) 63 | } 64 | 65 | func helper(root *TreeNode, min int, max int) bool { 66 | if root == nil { 67 | return true 68 | } 69 | 70 | if root.Val >= max || root.Val <= min { 71 | return false 72 | } 73 | return helper(root.Left, min, root.Val) && helper(root.Right, root.Val, max) 74 | } 75 | // @lc code=end 76 | 77 | -------------------------------------------------------------------------------- /go/leetcode/Readme.md: -------------------------------------------------------------------------------- 1 | ## 思路总结 2 | 3 | ### 分解 4 | 1. 分析问题,得到多个需求点 5 | 2. 单独对每个需求点思考,对每个需求点挑选合适的数据结构与算法 6 | 3. 考虑需求点之间的关系,如何串联起来 7 | 8 | eg1: LRU cache实现 9 | 10 | 分析需求点及对应方案: 11 | 1. 支持put_kv、get_k、del_k方法,锁定哈希map 12 | 2. 支持LRU规则清理,按使用时间线性排序,而且每次操作会修改排序,锁定双向链表 13 | 3. 每次操作key需要修改排序,需要根据key定位到链表,哈希map存链表节点指针 14 | 4. LRU清理key需要抹掉记录,链表中需要存key 15 | 16 | 总结整体方案:使用哈希map和双向链表,相互指向。 17 | 18 | eg2:86链表分隔实现 19 | 20 | 分析需求点及对应方案: 21 | 1. 找到分隔点,也就是链表中第一个>=x的点。可以用一个额外变量存储节点,也可以定义一个flag表示已经找到分隔点 22 | 2. 分隔点之后的每个小于x的点都要移动到分隔点之前,需要存储可插入位置 23 | 3. 遍历链表时需要一个当前节点 24 | 4. 需要从当前节点断开,还要插入到目标位置,所以用前节点比较方便 25 | 26 | 总结整体方案:使用一个flag标识是否找到分隔点,使用一个临时节点存当前可插入的点,使用一个当前节点遍历链表;当找到分隔点之后,小于x的点都插入到临时节点之后。 27 | 28 | 29 | ### 要考虑问题规模 30 | 31 | 1. 小范围数据,暴力遍历效率很高。 32 | 2. 一次性需求,暴力遍历效率最高:如果需要额外数据结构,那么构造这个数据结构就需要一次遍历了,还不如直接一次遍历操作。 33 | 34 | ### 通用性 35 | 36 | 1. 比如链表反转、奇偶排列等,这些移动其实使用数组来做更加方便和通用。而且数组存指针的空间损耗很小,时间复杂度上多一次构建数组遍历和一次构建链表结果遍历,影响也不大。但是用数组的方式是一种几何到代数的转换,调整起来准确性可以简单得到严格证明。 37 | 38 | 39 | ## 正确性 40 | 41 | ### 边界情况 42 | 43 | > 循环终止条件,递归终止条件,条件判断等,最常见的是要不要等于边界,从0开始还是从1开始等 44 | 45 | 46 | -------------------------------------------------------------------------------- /go/leetcode/a.1_shopping_cart.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 购物车抽奖 4 | func food(code [][]int, cart []int) bool { 5 | return (&foodSol{}).call(code, 0, cart, 0) 6 | } 7 | 8 | type foodSol struct{} 9 | 10 | func (s *foodSol) call(code [][]int, cs int, food []int, fs int) bool { 11 | // i == 0 12 | if cs >= len(code) { 13 | return true 14 | } 15 | 16 | if fs >= len(food) { 17 | return false 18 | } 19 | 20 | // [[1,2] [2,-1, 3]] [2,1,2,2,3,3] 21 | for i := fs; i < len(food); i++ { 22 | match := true 23 | j := 0 24 | for j < len(code[cs]) { 25 | if code[cs][j] != -1 && code[cs][j] != food[i+j] { 26 | match = false 27 | break 28 | } 29 | j++ 30 | } 31 | if match && s.call(code, cs+1, food, i+j) { 32 | return true 33 | } 34 | 35 | } 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /go/leetcode/a.2_avg_age.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 找出平均年龄最大的团队 4 | type employerNode struct { 5 | Val int 6 | Sub []*employerNode 7 | } 8 | 9 | type employerSol struct { 10 | sum int 11 | cnt int 12 | oldest float32 13 | } 14 | 15 | func (e *employerSol) call(root *employerNode) (sum int, cnt int) { 16 | if root == nil { 17 | return 0, 0 18 | } 19 | sum, cnt = root.Val, 1 20 | if len(root.Sub) <= 0 { 21 | return 22 | } 23 | for i := 0; i < len(root.Sub); i++ { 24 | s, c := e.call(root.Sub[i]) 25 | sum += s 26 | cnt += c 27 | } 28 | if cnt > 1 { 29 | avg := float32(sum) / float32(cnt) 30 | if avg > e.oldest { 31 | e.oldest = avg 32 | } 33 | } 34 | return 35 | } 36 | -------------------------------------------------------------------------------- /go/leetcode/a.4_continue_sum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 连续子串和 4 | func subArraySum(arr []int, target int) [][]int { 5 | s := &subArraySumSol{res: [][]int{}} 6 | s.call(arr, target) 7 | return s.res 8 | } 9 | 10 | type subArraySumSol struct { 11 | res [][]int 12 | } 13 | 14 | func (s *subArraySumSol) call(arr []int, target int) { 15 | for i := 0; i < len(arr); i++ { 16 | s.subArray(arr, target, i) 17 | } 18 | } 19 | 20 | func (s *subArraySumSol) subArray(arr []int, target int, left int) { 21 | // 找连续子串 22 | path := []int{} 23 | for i := left; i < len(arr); i++ { 24 | target -= arr[i] 25 | path = append(path, arr[i]) 26 | if target < 0 { // 泛化成连续子串和,如果还有负数则去掉该剪枝 27 | return 28 | } 29 | if target == 0 { 30 | s.res = append(s.res, append([]int{}, path...)) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /java/leetcode/1.两数之和.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | /* 4 | * @lc app=leetcode.cn id=1 lang=java 5 | * 6 | * [1] 两数之和 7 | * 8 | * https://leetcode-cn.com/problems/two-sum/description/ 9 | * 10 | * algorithms 11 | * Easy (47.01%) 12 | * Likes: 6956 13 | * Dislikes: 0 14 | * Total Accepted: 687.9K 15 | * Total Submissions: 1.5M 16 | * Testcase Example: '[2,7,11,15]\n9' 17 | * 18 | * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 19 | * 20 | * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 21 | * 22 | * 示例: 23 | * 24 | * 给定 nums = [2, 7, 11, 15], target = 9 25 | * 26 | * 因为 nums[0] + nums[1] = 2 + 7 = 9 27 | * 所以返回 [0, 1] 28 | * 29 | * 30 | */ 31 | 32 | // @lc code=start 33 | class Solution { 34 | public int[] twoSum(int[] nums, int target) { 35 | HashMap m = new HashMap(); 36 | int[] res = new int[2]; 37 | for (int i = 0; i < nums.length; ++i) { 38 | if (m.containsKey(target - nums[i])) { 39 | res[0] = i; 40 | res[1] = m.get(target - nums[i]); 41 | break; 42 | } 43 | m.put(nums[i], i); 44 | } 45 | return res; 46 | } 47 | } 48 | // @lc code=end 49 | 50 | -------------------------------------------------------------------------------- /java/leetcode/11.盛最多水的容器.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=11 lang=java 3 | * 4 | * [11] 盛最多水的容器 5 | * 6 | * https://leetcode-cn.com/problems/container-with-most-water/description/ 7 | * 8 | * algorithms 9 | * Medium (61.94%) 10 | * Likes: 1195 11 | * Dislikes: 0 12 | * Total Accepted: 155K 13 | * Total Submissions: 250.1K 14 | * Testcase Example: '[1,8,6,2,5,4,8,3,7]' 15 | * 16 | * 给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 17 | * (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 18 | * 19 | * 说明:你不能倾斜容器,且 n 的值至少为 2。 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 26 | * 27 | * 28 | * 29 | * 示例: 30 | * 31 | * 输入:[1,8,6,2,5,4,8,3,7] 32 | * 输出:49 33 | * 34 | */ 35 | 36 | // @lc code=start 37 | class Solution { 38 | public int maxArea(int[] height) { 39 | int maxVol = 0, left = 0, right = height.length-1; 40 | while (left < right) { 41 | int vol, w; 42 | w = right-left; 43 | if (height[left] < height[right]) { 44 | vol = w*height[left]; 45 | left++; 46 | } else { 47 | vol = w*height[right]; 48 | right--; 49 | } 50 | maxVol = Math.max(maxVol, vol); 51 | } 52 | return maxVol; 53 | } 54 | } 55 | // @lc code=end 56 | 57 | -------------------------------------------------------------------------------- /java/leetcode/114.二叉树展开为链表.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=114 lang=java 3 | * 4 | * [114] 二叉树展开为链表 5 | * 6 | * https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/description/ 7 | * 8 | * algorithms 9 | * Medium (64.77%) 10 | * Likes: 179 11 | * Dislikes: 0 12 | * Total Accepted: 14.3K 13 | * Total Submissions: 21.9K 14 | * Testcase Example: '[1,2,5,3,4,null,6]' 15 | * 16 | * 给定一个二叉树,原地将它展开为链表。 17 | * 18 | * 例如,给定二叉树 19 | * 20 | * ⁠ 1 21 | * ⁠ / \ 22 | * ⁠ 2 5 23 | * ⁠/ \ \ 24 | * 3 4 6 25 | * 26 | * 将其展开为: 27 | * 28 | * 1 29 | * ⁠\ 30 | * ⁠ 2 31 | * ⁠ \ 32 | * ⁠ 3 33 | * ⁠ \ 34 | * ⁠ 4 35 | * ⁠ \ 36 | * ⁠ 5 37 | * ⁠ \ 38 | * ⁠ 6 39 | * 40 | */ 41 | 42 | // @lc code=start 43 | /** 44 | * Definition for a binary tree node. 45 | * public class TreeNode { 46 | * int val; 47 | * TreeNode left; 48 | * TreeNode right; 49 | * TreeNode(int x) { val = x; } 50 | * } 51 | */ 52 | class Solution { 53 | public void flatten(TreeNode root) { 54 | if (root == null) { 55 | return; 56 | } 57 | flatten(root.left); 58 | flatten(root.right); 59 | TreeNode tmp = root.right; 60 | root.right = root.left; 61 | root.left = null; 62 | while (root.right != null) { 63 | root = root.right; 64 | } 65 | root.right = tmp; 66 | } 67 | } 68 | // @lc code=end 69 | 70 | -------------------------------------------------------------------------------- /java/leetcode/16.最接近的三数之和.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=16 lang=java 3 | * 4 | * [16] 最接近的三数之和 5 | * 6 | * https://leetcode-cn.com/problems/3sum-closest/description/ 7 | * 8 | * algorithms 9 | * Medium (40.62%) 10 | * Likes: 187 11 | * Dislikes: 0 12 | * Total Accepted: 26.7K 13 | * Total Submissions: 65.8K 14 | * Testcase Example: '[-1,2,1,-4]\n1' 15 | * 16 | * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 17 | * 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 18 | * 19 | * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 20 | * 21 | * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 22 | * 23 | * 24 | */ 25 | 26 | // @lc code=start 27 | import java.util.*; 28 | import java.lang.Math; 29 | class Solution { 30 | public int threeSumClosest(int[] nums, int target) { 31 | Arrays.sort(nums); 32 | int res = nums[0] + nums[1] + nums[2]; 33 | for (int i = 0; i < nums.length-2; i++) { 34 | int j = i+1, k = nums.length -1; 35 | while (j < k) { 36 | int sum = nums[i] + nums[j] + nums[k]; 37 | if (Math.abs(target - sum) < Math.abs(target - res)) { 38 | res = sum; 39 | } 40 | if (sum > target) { 41 | k--; 42 | } else { 43 | j++; 44 | } 45 | } 46 | } 47 | return res; 48 | } 49 | } 50 | // @lc code=end 51 | 52 | -------------------------------------------------------------------------------- /java/leetcode/75.颜色分类.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=75 lang=java 3 | * 4 | * [75] 颜色分类 5 | * 6 | * https://leetcode-cn.com/problems/sort-colors/description/ 7 | * 8 | * algorithms 9 | * Medium (52.75%) 10 | * Likes: 266 11 | * Dislikes: 0 12 | * Total Accepted: 43K 13 | * Total Submissions: 79.9K 14 | * Testcase Example: '[2,0,2,1,1,0]' 15 | * 16 | * 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 17 | * 18 | * 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 19 | * 20 | * 注意: 21 | * 不能使用代码库中的排序函数来解决这道题。 22 | * 23 | * 示例: 24 | * 25 | * 输入: [2,0,2,1,1,0] 26 | * 输出: [0,0,1,1,2,2] 27 | * 28 | * 进阶: 29 | * 30 | * 31 | * 一个直观的解决方案是使用计数排序的两趟扫描算法。 32 | * 首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 33 | * 你能想出一个仅使用常数空间的一趟扫描算法吗? 34 | * 35 | * 36 | */ 37 | 38 | // @lc code=start 39 | class Solution { 40 | public void sortColors(int[] nums) { 41 | if (nums.length <= 1) { 42 | return; 43 | } 44 | int left = 0, current = 0, right = nums.length - 1; 45 | // 2,0,2,1,1,0 46 | while (current <= right) { 47 | if (nums[current] == 0) { 48 | swap(nums, current, left); // 0,2,2,1,1,0 49 | left++; 50 | current++; 51 | } else if (nums[current] == 2) { 52 | swap(nums, current, right); 53 | right--; 54 | } else { 55 | current++; // 1 56 | } 57 | } 58 | } 59 | 60 | public void swap(int[] nums, int i, int j) { 61 | int tmp; 62 | tmp = nums[i]; 63 | nums[i] = nums[j]; 64 | nums[j] = tmp; 65 | } 66 | } 67 | // @lc code=end 68 | -------------------------------------------------------------------------------- /js/framework/Angular/angular_mvvm_ver0.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular MVVM模式的简单实现_原始版 6 | 7 | 8 |

mvvm simple model

9 |
10 |

绑定测试:

11 |

不同绑定测试:

12 | 13 | 14 | 15 |
16 | 17 | 37 | 38 | -------------------------------------------------------------------------------- /js/framework/Vue/lib/Observer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @authors : qieguo 3 | * @date : 2016/12/13 4 | * @version : 1.0 5 | * @description : Observer,实现对viewModel的监控,当发生变更时发出变更消息 6 | */ 7 | 8 | function Observer(data) { 9 | this.data = data; 10 | this.observe(data); 11 | } 12 | 13 | // Observer //@todo 未对数组监控,可以劫持Array的原型实现 14 | Observer.prototype.observe = function (data) { 15 | var self = this; 16 | // 设置开始和递归终止条件 17 | if (!data || typeof data !== 'object') { 18 | return; 19 | } 20 | // 不能直接使用for循环,避开闭包陷阱 21 | Object.keys(data).forEach(function (key) { 22 | self.defineReactive(data, key, data[key]); 23 | }); 24 | } 25 | 26 | Observer.prototype.defineReactive = function (data, key, val) { 27 | var dep = new Dep(); 28 | var self = this; 29 | self.observe(val); // 递归对象属性到基本类型为止 30 | Object.defineProperty(data, key, { 31 | enumerable : true, // 枚举 32 | configurable: false, // 不可再配置 33 | get : function () { 34 | // console.log('getter dep', dep); 35 | // 由于需要在闭包内添加watcher,所以通过Dep定义一个全局target属性,暂存watcher, 添加完移除 36 | Dep.target && dep.addSub(Dep.target); 37 | return val; 38 | }, 39 | set : function (newVal) { 40 | if (val === newVal) { 41 | return; 42 | } 43 | // console.log('setter dep', dep); 44 | val = newVal; // setter本身已经做了赋值,val作为一个闭包变量,保存最新值 45 | self.observe(newVal); 46 | dep.notify(); // 触发通知 47 | }, 48 | }) 49 | } -------------------------------------------------------------------------------- /js/framework/Vue/lib/Watcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @authors : qieguo 3 | * @date : 2016/12/15 4 | * @version : 1.0 5 | * @description : Watcher,订阅Observer的变更消息,获取最新值计算表达式,通过回调函数(updater函数)将计算结果更新到视图上 6 | */ 7 | 8 | var $uid = 0; 9 | 10 | function Watcher(exp, scope, callback) { 11 | this.exp = exp; 12 | this.scope = scope; 13 | this.callback = callback || function () {}; 14 | 15 | //初始化时,触发添加到监听队列 16 | this.value = null; 17 | this.uid = $uid++; 18 | this.update(); 19 | } 20 | 21 | // 解析表达式 with+eval会将表达式中的变量绑定到vm模型中,从而实现对变量的取值, 22 | function computeExpression(exp, scope) { 23 | try { 24 | with (scope) { 25 | return eval(exp); 26 | } 27 | } catch (e) { 28 | console.error('ERROR', e); 29 | } 30 | 31 | // with (scope) { 32 | // return eval(exp); 33 | // } 34 | 35 | } 36 | 37 | Watcher.prototype = { 38 | get: function () { 39 | Dep.target = this; 40 | var value = computeExpression(this.exp, this.scope); //执行的时候添加监听 41 | //在parseExpression的时候,with + eval会将表达式中的变量绑定到vm模型中,在求值的时候会调用相应变量的getter事件。 42 | //由于设置了Dep.target,所以会执行observer的add.sub方法,从而创建了一个依赖链。 43 | Dep.target = null; 44 | return value; 45 | }, 46 | update: function () { 47 | var newVal = this.get(); 48 | if (this.value != newVal) { 49 | this.callback && this.callback(newVal, this.value); 50 | this.value = newVal; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /js/framework/Vue/lib/dependence.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @authors : qieguo 3 | * @date : 2016/12/15 4 | * @version : 1.0 5 | * @description : 6 | */ 7 | 8 | // dependence 9 | function Dep() { 10 | this.subs = {}; 11 | }; 12 | 13 | Dep.prototype.addSub = function (target) { 14 | if (!this.subs[target.uid]) { //防止重复添加 15 | this.subs[target.uid] = target; 16 | } 17 | }; 18 | 19 | Dep.prototype.notify = function () { 20 | for (var uid in this.subs) { 21 | this.subs[uid].update(); 22 | } 23 | }; -------------------------------------------------------------------------------- /js/recursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @authors : qieguo 3 | * @date : 2017/1/2 0002 4 | * @version : 1.0 5 | * @description : 一些递归算法 6 | */ 7 | 8 | 'use strict'; 9 | 10 | /** 11 | * 阶梯问题 12 | * 假设一个楼梯有 N 阶台阶,人每次最多可以跨 M 阶,求总共的爬楼梯方案数。 13 | * 例如楼梯总共有3个台阶,人每次最多跨2个台阶,也就是说人每次可以走1个,也可以走2个,但最多不会超过2个,那么楼梯总共有这么几种走法: 14 | * 111,12,21 15 | */ 16 | 17 | var methods = [] 18 | function countSteps(steps, max, method) { 19 | method = method || ''; 20 | if(steps === 0) { 21 | methods.push(method); 22 | return method; 23 | } 24 | if(steps < max) { 25 | countSteps(steps, steps, method) 26 | } else { 27 | for(var i = 1; i <= max; i++) { 28 | countSteps(steps - i, max, method + String(i)); 29 | } 30 | } 31 | } 32 | 33 | countSteps(4, 3); 34 | console.log('methods', methods); 35 | 36 | /** 37 | * 链式函数 38 | * 编写阶乘函数 fn,使得 fn(2)(3) = 6,fn(2)(3)(4) = 24 39 | * 这里用到递归、函数柯里化、valueOf几个点,注意()运算符是从左到右执行的 40 | */ 41 | function mul(x) { 42 | const fn = y => mul(x * y); // 返回一个函数,函数参数里面做乘法运算 43 | fn.valueOf = () => x; // 改写valueOf,在链式运算最后一步输出结果 44 | return fn; 45 | } 46 | 47 | /** 48 | * 汉诺塔问题 49 | * 编写函数输出汉诺塔移动轨迹,move(n, a, b, c),n为盘子数量,a为源头,b为中转柱子,c为目标柱子 50 | */ 51 | function move(n, a, b, c) { 52 | if(n === 1) { 53 | console.log(`${a} --> ${c}`); 54 | } else { 55 | move(n - 1, a, c, b); 56 | move(1, a, b, c); 57 | move(n - 1, b, a, c) 58 | } 59 | } 60 | 61 | // move(5, 'A', 'B', 'C'); 62 | -------------------------------------------------------------------------------- /js/tree.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @authors : qieguo 3 | * @date : 2017/1/2 4 | * @version : 1.0 5 | * @description : 树相关算法(二叉树、二叉查找数、堆) 6 | */ 7 | 8 | 'use strict'; 9 | 10 | function BinaryRearchTree(arr) { 11 | 12 | function init() { 13 | if (!Array.isArray(arr)) { 14 | console.error(arr + ' is not a Array'); 15 | return false; 16 | } 17 | 18 | } 19 | 20 | 21 | } 22 | 23 | 24 | /** 25 | * 堆排序 26 | * 应用:用尺寸为n的最小堆(最大堆)来筛选大数据集里面最大(小)的n个数 27 | * 流程: 28 | * 1)先使用数据集里面的前n条数据来构造最小堆 29 | * 2)遍历数据集,将每个数据与堆顶元素比较,若小于堆顶则抛弃,否则替换掉堆顶 30 | * 3)调整替换后的堆,继续2) 31 | * 32 | * 用有序数组+2分查找也是类似的,不过效率低一些。 33 | */ 34 | -------------------------------------------------------------------------------- /md/js中的树.md: -------------------------------------------------------------------------------- 1 | ## 树 2 | 3 | -------------------------------------------------------------------------------- /resource/Array001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qieguo2016/algorithm/fa6975f85d24c8753335189c88995231f85fc533/resource/Array001.png -------------------------------------------------------------------------------- /resource/Chain001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qieguo2016/algorithm/fa6975f85d24c8753335189c88995231f85fc533/resource/Chain001.jpg -------------------------------------------------------------------------------- /resource/array__003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qieguo2016/algorithm/fa6975f85d24c8753335189c88995231f85fc533/resource/array__003.jpg -------------------------------------------------------------------------------- /resource/hashmap__004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qieguo2016/algorithm/fa6975f85d24c8753335189c88995231f85fc533/resource/hashmap__004.jpg -------------------------------------------------------------------------------- /resource/object__001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qieguo2016/algorithm/fa6975f85d24c8753335189c88995231f85fc533/resource/object__001.jpg -------------------------------------------------------------------------------- /resource/object__002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qieguo2016/algorithm/fa6975f85d24c8753335189c88995231f85fc533/resource/object__002.jpg --------------------------------------------------------------------------------