├── ACM ├── poj 1051 P,MTHBGWB.md ├── poj 1077 Eight.md ├── poj 1090 Chain.md ├── poj 1127 Jack Straws.md ├── poj 1149 PIGS.md ├── poj 1153 SAFE.md ├── poj 1184 聪明的打字员.md ├── poj 1205 Water Treatment Plants.md ├── poj 1240 Pre-Post-erous!.md ├── poj 1284 Primitive Roots.md ├── poj 1308 Is It A Tree?.md ├── poj 1313 Booklet Printing.md ├── poj 1353 Color Change of Go Game Pieces.md ├── poj 1417 True Liars.md ├── poj 1459 Power Network.md ├── poj 1480 Optimal Programs.md ├── poj 1523 SPF.md ├── poj 1534 Terrorist Attack.md ├── poj 1559 Equation Elation.md ├── poj 1611 The Suspects.md ├── poj 1619 EKG Sequence.md ├── poj 1628 Deduction.md ├── poj 1650 Integer Approximation.md ├── poj 1663 Number Steps.md ├── poj 1664 放苹果.md ├── poj 1690 Your-Term-Project.md ├── poj 1780 Code.md ├── poj 1789 Truck History.md ├── poj 1909 Marbles on a tree.md ├── poj 1953 World Cup Noise.md ├── poj 1972 Dice Stacking.md ├── poj 1977 Odd Loving Bakers.md ├── poj 1984 Navigation Nightmare.md ├── poj 1989 The Cow Lineup.md ├── poj 2007 Scrambled Polygon.md ├── poj 2174 Decoding Task.md ├── poj 2196 Specialized Four-Digit Numbers.md ├── poj 2201 Cartesian Tree.md ├── poj 2206 Magic Multiplying Machine.md ├── poj 2323 PERMS.md ├── poj 2362 Square.md ├── poj 2386 Lake Counting.md ├── poj 2403 Hay Points.md ├── poj 2409 Let it Bead.md ├── poj 2417 Discrete Logging.md ├── poj 2430 Lazy Cows.md ├── poj 2442 Sequence.md ├── poj 2447 RSA.md ├── poj 2452 Sticks Problem.md ├── poj 2458 Rigging the Bovine Election.md ├── poj 2482 Stars in Your Window.md ├── poj 2506 Tiling.md ├── poj 2622 Convex hull.md ├── poj 2664 Prerequisites?.md ├── poj 2668 Defending Castle.md ├── poj 2672 Hotkeys.md ├── poj 2679 Adventurous Driving.md ├── poj 2749 Building roads.md ├── poj 2771 Guardian of Decency.md ├── poj 2817 WordStack.md ├── poj 2827 Auto-Calculation Machine.md ├── poj 2893 M × N Puzzle.md ├── poj 2900 Griddy Hobby.md ├── poj 2903 Joy of Mobile Routing.md ├── poj 2918 Tudoku.md ├── poj 2941 Homogeneous Squares.md ├── poj 2978 Colored stones.md ├── poj 3050 Hopscotch.md ├── poj 3071 Football.md ├── poj 3131 Cubic Eight-Puzzle.md ├── poj 3174 Alignment of the Planets.md ├── poj 3183 Stump Removal.md ├── poj 3191 The Moronic Cowmpouter.md ├── poj 3196 Babylonian Roulette.md ├── poj 3216 Repairing Company.md ├── poj 3219 Binomial Coefficients.md ├── poj 3222 Edge Pairing.md ├── poj 3260 The Fewest Coins.md ├── poj 3266 Cow School.md ├── poj 3294 Life Forms.md ├── poj 3349 Snowflake Snow Snowflakes.md ├── poj 3356 AGTC.md ├── poj 3361 Gaussian Prime Factors.md ├── poj 3363 Annoying painting tool.md ├── poj 3376 Finding Palindromes.md ├── poj 3388 Japanese Puzzle.md ├── poj 3435 Sudoku Checker.md ├── poj 3449 Geometric Shapes.md ├── poj 3481 Double Queue.md ├── poj 3484 Showstopper.md ├── poj 3495 Bitwise XOR of Arithmetic Progression.md ├── poj 3532 Resistance.md ├── poj 3548 Restoring the digits.md ├── poj 3554 Almost the shortest route.md ├── poj 3573 I18n.md ├── poj 3579 Median.md ├── poj 3585 Accumulation Degree.md ├── poj 3593 Sea Base Exploration.md ├── poj 3612 Telephone Wire.md ├── poj 3623 Best Cow Line, Gold.md ├── poj 3632 Optimal Parking.md ├── poj 3635 Full Tank?.md ├── poj 3715 Blue and Red.md ├── poj 3752 字母旋转游戏.md ├── poj 3757 Simple Distributed storage system.md ├── poj 3763 Tour in Wonder Land.md ├── poj 3782 Equal Sum Partitions.md ├── poj 3802 Cubist Artwork.md ├── poj 3860 Fruit Weights.md ├── poj 3883 Penguin Bashing.md ├── poj 3901 The Computer Game.md ├── poj 3910 GCD Determinant.md ├── poj 3914 DuLL.md ├── poj 3987 Computer Virus on Planet Pandora.md ├── poj 4003 Bob’s Race.md ├── poj 4006 Genghis Khan the Conqueror.md ├── zoj 1119 SPF.md ├── zoj 1179 Finding Rectangles.md ├── zoj 1204 Additive equations.md ├── zoj 1237 Fans and Gems.md ├── zoj 1255 The Path.md ├── zoj 1259 Rails.md ├── zoj 1279 Cowculations.md ├── zoj 1325 Palindromes.md ├── zoj 1344 A Mazing Problem.md ├── zoj 1400 Programmer, Rank Thyself.md ├── zoj 1404 Oil Pipeline.md ├── zoj 1418 Lazy Math Instructor.md ├── zoj 1433 Treasure Hunters.md ├── zoj 1472 Overlapping Shapes.md ├── zoj 1496 Best Fit.md ├── zoj 1497 Ball Toss.md ├── zoj 1501 Knockout Tournament.md ├── zoj 1507 Crazy Search.md ├── zoj 1535 Lucky Ticket.md ├── zoj 1563 Pearls.md ├── zoj 1566 Too Lazy To Move.md ├── zoj 1610 Count the Colors.md ├── zoj 1671 Walking Ant.md ├── zoj 1743 Concert Hall Scheduling.md ├── zoj 1797 Least Common Multiple.md ├── zoj 1810 The Gourmet Club.md ├── zoj 1812 Stamps.md ├── zoj 1861 Gas Station Numbers.md ├── zoj 1898 Discrete Logging.md ├── zoj 1966 Etaoin Shrdlu.md ├── zoj 2009 Run Away.md ├── zoj 2011 Secret Code.md ├── zoj 2139 ACM.md ├── zoj 2151 The Highest Profits.md ├── zoj 2191 Series Determination.md ├── zoj 2247 Magic Trick.md ├── zoj 2316 Matrix Multiplication.md ├── zoj 2361 Areas.md ├── zoj 2451 Minimizing maximizer.md ├── zoj 2499 The Happy Worm.md ├── zoj 2561 Order-Preserving Codes.md ├── zoj 2594 Driving Straight.md ├── zoj 2634 Collecting Stones.md ├── zoj 2665 Heapsort.md ├── zoj 2671 Cryptography.md ├── zoj 2725 Digital Deletions.md ├── zoj 2814 Surprising Strings.md ├── zoj 2837 Left Library Lift.md ├── zoj 2886 Look and Say.md ├── zoj 2898 Greedy Grave Robber.md ├── zoj 2913 Bus Pass.md ├── zoj 2990 Decoding.md ├── zoj 2993 Model Rocket Height.md ├── zoj 3016 Cut.md ├── zoj 3019 Puzzle.md ├── zoj 3049 Diablo II Items.md ├── zoj 3051 Playing Poker.md ├── zoj 3109 Decode Message.md ├── zoj 3114 Double Queue.md ├── zoj 3134 Travel.md ├── zoj 3151 Dice Compare.md ├── zoj 3212 K-Nice.md ├── zoj 3235 Prototype.md ├── zoj 3291 Never End.md ├── zoj 3347 Picture Handling.md ├── zoj 3385 Hanami Party.md ├── zoj 3393 Routing.md ├── zoj 3502 Contest.md ├── zoj 3531 Alice Madness Return.md ├── zoj 3590 -3+1.md ├── zoj 3595 Two Sequences.md ├── zoj 3634 Bounty hunter.md ├── zoj 3661 Palindromic Substring.md ├── zoj 3663 Polaris of Pandora.md ├── zoj 3690 Choosing number.md ├── zoj 3770 Ranking System.md ├── zoj 3795 Grouping.md ├── zoj 3798 Abs Problem.md ├── zoj 3805 Machine.md ├── zoj 3811 Untrusted Patrol.md ├── zoj 3813 Alternating Sum.md ├── zoj 3836 Circulation pipe.md ├── zoj 3890 Wumpus.md └── zoj 3898 Stean.md ├── README.md ├── contact.jpg ├── leetcode ├── 1.txt ├── Excel表列名称.md ├── Excel表列序号.md ├── K 个一组翻转链表.md ├── LRU 缓存机制.md ├── N 皇后 II.md ├── N 皇后.md ├── Pow(x, n).md ├── Z 字形变换.md ├── x 的平方根.md ├── 三数之和.md ├── 三角形最小路径和.md ├── 下一个排列.md ├── 不同的二叉搜索树 II.md ├── 不同的二叉搜索树.md ├── 不同的子序列.md ├── 不同路径 II.md ├── 不同路径.md ├── 两两交换链表中的节点.md ├── 两数之和 II - 输入有序数组.md ├── 两数之和.md ├── 两数相加.md ├── 两数相除.md ├── 串联所有单词的子串.md ├── 乘积最大子数组.md ├── 买卖股票的最佳时机 II.md ├── 买卖股票的最佳时机 III.md ├── 买卖股票的最佳时机.md ├── 二叉搜索树迭代器.md ├── 二叉树中的最大路径和.md ├── 二叉树展开为链表.md ├── 二叉树的中序遍历.md ├── 二叉树的前序遍历.md ├── 二叉树的右视图.md ├── 二叉树的后序遍历.md ├── 二叉树的层序遍历 II.md ├── 二叉树的层序遍历.md ├── 二叉树的最大深度.md ├── 二叉树的最小深度.md ├── 二叉树的锯齿形层序遍历.md ├── 二进制求和.md ├── 交错字符串.md ├── 从中序与后序遍历序列构造二叉树.md ├── 从前序与中序遍历序列构造二叉树.md ├── 位1的个数.md ├── 克隆图.md ├── 全排列 II.md ├── 全排列.md ├── 分割回文串 II.md ├── 分割回文串.md ├── 分发糖果.md ├── 分数到小数.md ├── 分隔链表.md ├── 删除排序链表中的重复元素 II.md ├── 删除排序链表中的重复元素.md ├── 删除有序数组中的重复项 II.md ├── 删除有序数组中的重复项.md ├── 删除链表的倒数第 N 个结点.md ├── 加一.md ├── 加油站.md ├── 单词拆分 II.md ├── 单词拆分.md ├── 单词接龙 II.md ├── 单词接龙.md ├── 单词搜索 II.md ├── 单词搜索.md ├── 反转链表 II.md ├── 反转链表.md ├── 只出现一次的数字 II.md ├── 只出现一次的数字.md ├── 合并K个升序链表.md ├── 合并两个有序数组.md ├── 合并两个有序链表.md ├── 合并区间.md ├── 同构字符串.md ├── 四数之和.md ├── 回文数.md ├── 在排序数组中查找元素的第一个和最后一个位置.md ├── 地下城游戏.md ├── 基本计算器.md ├── 填充每个节点的下一个右侧节点指针 II.md ├── 填充每个节点的下一个右侧节点指针.md ├── 复制带随机指针的链表.md ├── 复原 IP 地址.md ├── 外观数列.md ├── 多数元素.md ├── 子集 II.md ├── 子集.md ├── 字母异位词分组.md ├── 字符串相乘.md ├── 字符串转换整数.md ├── 存在重复元素 II.md ├── 存在重复元素 III.md ├── 实现 Trie (前缀树).md ├── 实现 strStr().md ├── 对称二叉树.md ├── 对链表进行插入排序.md ├── 寻找两个正序数组的中位数 .md ├── 寻找峰值.md ├── 寻找旋转排序数组中的最小值 II.md ├── 寻找旋转排序数组中的最小值.md ├── 将有序数组转换为二叉搜索树.md ├── 岛屿数量.md ├── 平衡二叉树.md ├── 快乐数.md ├── 恢复二叉搜索树.md ├── 打家劫舍 II.md ├── 打家劫舍.md ├── 扰乱字符串.md ├── 括号生成.md ├── 排列序列.md ├── 排序链表.md ├── 接雨水.md ├── 插入区间.md ├── 搜索二维矩阵.md ├── 搜索插入位置.md ├── 搜索旋转排序数组 II.md ├── 搜索旋转排序数组.md ├── 数字范围按位与.md ├── 数组中的第K个最大元素.md ├── 整数反转.md ├── 整数转罗马数字.md ├── 文本左右对齐.md ├── 旋转图像.md ├── 旋转数组.md ├── 旋转链表.md ├── 无重复字符的最长子串.md ├── 最后一个单词的长度.md ├── 最大子序和.md ├── 最大正方形.md ├── 最大矩形.md ├── 最大间距.md ├── 最小栈.md ├── 最小覆盖子串.md ├── 最小路径和.md ├── 最接近的三数之和.md ├── 最短回文串.md ├── 最长公共前缀.md ├── 最长回文子串.md ├── 最长有效括号.md ├── 最长连续序列.md ├── 有序链表转换二叉搜索树.md ├── 有效数字.md ├── 有效的括号.md ├── 有效的数独.md ├── 杨辉三角 II.md ├── 杨辉三角.md ├── 柱状图中最大的矩形.md ├── 格雷编码.md ├── 正则表达式匹配.md ├── 比较版本号.md ├── 求根节点到叶节点数字之和.md ├── 添加与搜索单词 - 数据结构设计.md ├── 爬楼梯.md ├── 环形链表 II.md ├── 环形链表.md ├── 电话号码的字母组合.md ├── 盛最多水的容器.md ├── 直线上最多的点数.md ├── 相交链表.md ├── 相同的树.md ├── 矩阵置零.md ├── 移除元素.md ├── 移除链表元素.md ├── 第二高的薪水.md ├── 简化路径.md ├── 组合.md ├── 组合两个表.md ├── 组合总和 II.md ├── 组合总和 III.md ├── 组合总和.md ├── 编辑距离.md ├── 缺失的第一个正数.md ├── 罗马数字转整数.md ├── 翻转二叉树.md ├── 翻转字符串里的单词.md ├── 螺旋矩阵 II.md ├── 螺旋矩阵.md ├── 被围绕的区域.md ├── 解数独.md ├── 解码方法.md ├── 计数质数.md ├── 课程表 II.md ├── 课程表.md ├── 路径总和 II.md ├── 路径总和.md ├── 跳跃游戏 II.md ├── 跳跃游戏.md ├── 逆波兰表达式求值.md ├── 通配符匹配.md ├── 重排链表.md ├── 长度最小的子数组.md ├── 阶乘后的零.md ├── 颜色分类.md ├── 颠倒二进制位.md ├── 验证二叉搜索树.md └── 验证回文串.md ├── mysql ├── 1.txt ├── 1~100mysql的面试题.md ├── MySQL 索引使用有哪些注意事项呢?.md ├── MySQL 遇到过死锁问题吗,你是如何解决的?.md ├── 日常工作中你是怎么优化SQL的?.md └── 说说分库与分表的设计.md ├── nginx ├── 1.txt └── 1~32 Nginx面试题.md ├── redis ├── 1.txt └── 1~50Redis面试题.md ├── 剑指offer ├── 0到n-1中缺失的数字.md ├── 1.txt ├── 64位整数乘法.md ├── A + B.md ├── a^b.md ├── 七夕祭.md ├── 不修改数组找出重复的数字.md ├── 不分行从上往下打印二叉树.md ├── 不用加减乘除做加法.md ├── 丑数.md ├── 两个链表的第一个公共结点.md ├── 之字形打印二叉树.md ├── 二叉搜索树与双向链表.md ├── 二叉搜索树的后序遍历序列.md ├── 二叉搜索树的第k个结点.md ├── 二叉树中和为某一值的路径.md ├── 二叉树的下一个节点.md ├── 二叉树的深度.md ├── 二叉树的镜像.md ├── 二维数组中的查找.md ├── 二维费用的背包问题.md ├── 二进制中1的个数.md ├── 从1到n整数中1出现的次数.md ├── 从尾到头打印链表.md ├── 任务.md ├── 你玩过“拉灯”游戏吗?.md ├── 兔子与兔子.md ├── 分形.md ├── 分形之城..md ├── 分组背包问题.md ├── 分行从上往下打印二叉树.md ├── 删除链表中重复的节点.md ├── 判断该树是不是平衡二叉树.md ├── 前缀统计.md ├── 剪绳子.md ├── 动态中位数.md ├── 包含min函数的栈.md ├── 占卜DIY .md ├── 双端队列.md ├── 反转链表.md ├── 合并两个排序的链表.md ├── 合并果子.md ├── 后缀数组.md ├── 周期.md ├── 和为S的两个数字.md ├── 和为S的连续正数序列.md ├── 回文子串的最大长度.md ├── 国王游戏.md ├── 圆圈中最后剩下的数字.md ├── 在O(1)时间删除链表结点.md ├── 增减序列.md ├── 士兵.md ├── 复杂链表的复刻.md ├── 多重背包问题 I.md ├── 多重背包问题 II.md ├── 多重背包问题 III.md ├── 天才ACM.md ├── 奇怪的汉诺塔.md ├── 奇数码问题.md ├── 字符串中第一个只出现一次的字符.md ├── 字符流中第一个只出现一次的字符(1).md ├── 完全背包问题.md ├── 对称的二叉树.md ├── 小组队列.md ├── 左旋转字符串.md ├── 序列.md ├── 序列化二叉树.md ├── 扑克牌的顺子.md ├── 找出数组中重复的数字.md ├── 把字符串转换成整数.md ├── 把数字翻译成字符串.md ├── 把数组排成最小的数.md ├── 括号画家.md ├── 数值的整数次方.md ├── 数字在排序数组中出现的次数.md ├── 数字序列中某一位的数字.md ├── 数字排列.md ├── 数据备份.md ├── 数据流中的中位数.md ├── 数的进制转换.md ├── 数组中出现次数超过一半的数字.md ├── 数组中只出现一次的两个数字.md ├── 数组中唯一只出现一次的数字.md ├── 数组中数值和下标相等的元素.md ├── 数组中的逆序对.md ├── 斐波那契数列.md ├── 旋转数组的最小数字.md ├── 是否存在两片形状相同的雪花?.md ├── 替换空格.md ├── 最佳牛围栏.md ├── 最大子序和.md ├── 最大异或对.md ├── 最大的和.md ├── 最小的k个数.md ├── 最短Hamilton路径.md ├── 最长不含重复字符的子字符串.md ├── 最长异或值路径.md ├── 最高的牛.md ├── 有依赖的背包问题.md ├── 机器人的运动范围.md ├── 构建乘积数组.md ├── 栈的压入、弹出序列.md ├── 树中两个结点的最低公共祖先.md ├── 树的子结构.md ├── 正则表达式匹配.md ├── 求1+2+…+n.md ├── 混合背包问题.md ├── 滑动窗口的最大值.md ├── 激光炸弹.md ├── 火车进出栈问题.md ├── 火车进栈.md ├── 特殊排序.md ├── 用两个栈实现队列.md ├── 电影.md ├── 畜栏预定.md ├── 直方图中最大的矩形.md ├── 矩阵中的路径.md ├── 礼物的最大价值.md ├── 糖果传递.md ├── 约数之和.md ├── 给树染色.md ├── 编辑器.md ├── 翻转单词顺序.md ├── 耍杂技的牛.md ├── 股票的最大利润.md ├── 背包问题.md ├── 背包问题求具体方案.md ├── 背包问题求方案数.md ├── 荷马史诗.md ├── 蚯蚓.md ├── 表示数值的字符串.md ├── 袭击.md ├── 调整数组顺序使奇数位于偶数前面.md ├── 货仓选址.md ├── 赶牛入圈.md ├── 超市.md ├── 超快速排序.md ├── 连续子数组的最大和.md ├── 递归实现指数型枚举 .md ├── 递归实现排列型枚举.md ├── 递归实现组合型枚举.md ├── 邻值查找.md ├── 重建二叉树.md ├── 链表中倒数第k个节点.md ├── 链表中环的入口结点.md ├── 防晒.md ├── 防线.md ├── 雷达设备 .md ├── 顺时针打印矩阵.md ├── 飞行员兄弟.md └── 骰子的点数.md ├── 图 └── 1.txt ├── 堆与栈 └── 1.txt ├── 字符串 └── 1.txt ├── 并发 ├── 1.txt └── 1~14 并发面试题.md ├── 排序 └── 1.txt ├── 操作系统 ├── 1.txt └── 1~18 操作系统面试题.md ├── 树 └── 1.txt ├── 编译原理 ├── 1.txt └── 1~9 编译原理面试题.md ├── 网络原理 ├── 1.txt └── 1~36 网络原理面试题.md ├── 网络编程 ├── 1.txt └── 1~25 网络编程面试题.md └── 语言语法 ├── 1.txt └── 1~103 语言语法面试题.md /ACM/poj 1284 Primitive Roots.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | We say that integer x, 0 i mod p) | 1 Write a program which given any odd prime 3 3 | 4 | 输入描述 5 | 6 | Each line of the input contains an odd prime numbers p. Input is terminated by the end-of-file seperator. 7 | 8 | 输出描述 9 | 10 | For each p, print a single number that gives the number of primitive roots in a single line. 11 | 12 | 输入例子 13 | ``` 14 | 23 15 | 31 16 | 79 17 | ``` 18 | 输出例子 19 | ``` 20 | 10 21 | 8 22 | 24 23 | ``` 24 | # 参考答案 25 | ```c++ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | using namespace std; 33 | int phi[66000]; 34 | int main() 35 | { 36 | int i , j ; 37 | for ( i = 2 ; i <= 65536 ; i ++ ) 38 | phi[i]=0; 39 | phi[1]=1; 40 | for ( i = 2 ; i <= 65536 ; i ++ ) 41 | if ( !phi[i] ) 42 | { 43 | for ( j = i ; j <= 65536 ; j += i ) 44 | { 45 | if ( !phi[j] ) 46 | phi[j] = j ; 47 | phi[j] = phi[j] / i * (i - 1 ) ; 48 | } 49 | } 50 | 51 | int n ; 52 | while ( cin >> n ) 53 | cout< 22 | 23 | int fun(int m,int n) //m个苹果放在n个盘子***有几种方法 24 | { 25 | if(m==0||n==1) //因为我们总是让m>=n来求解的,所以m-n>=0,所以让m=0时候结束,如果改为m=1, 26 | return 1; //则可能出现m-n=0的情况从而不能得到正确解 27 | if(n>m) 28 | return fun(m,m); 29 | else 30 | return fun(m,n-1)+fun(m-n,n); 31 | } 32 | 33 | int main() 34 | { 35 | int T,m,n; 36 | scanf("%d",&T); 37 | while(T--) 38 | { 39 | scanf("%d%d",&m,&n); 40 | printf("%d\n",fun(m,n)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ACM/poj 3219 Binomial Coefficients.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | The binomial coefficient C(n, k) has been extensively studied for its importance in combinatorics. Binomial coefficients can be recursively defined as follows: 3 | ``` 4 | C(n, 0) = C(n, n) = 1 for all n > 0; 5 | C(n, k) = C(n − 1, k − 1) + C(n − 1, k) for all 0 < k < n. 6 | ``` 7 | Given n and k, you are to determine the parity of C(n, k). 8 | 9 | 输入描述
10 | The input contains multiple test cases. Each test case consists of a pair of integers n and k (0 ≤ k ≤ n < 231, n > 0) on a separate line. 11 | 12 | End of file (EOF) indicates the end of input. 13 | 14 | 输出描述
15 | For each test case, output one line containing either a “0” or a “1”, which is the remainder of C(n, k) divided by two. 16 | 17 | 输入例子 18 | ``` 19 | 1 1 20 | 1 0 21 | 2 1 22 | ``` 23 | 输出例子 24 | ``` 25 | 1 26 | 1 27 | 0 28 | ``` 29 | # 参考答案 30 | ```c++ 31 | #include 32 | int main() 33 | { 34 | int a, b; 35 | while (scanf("%d%d", &a, &b) == 2) { 36 | printf("%d\n", (a - b) & b ? 0 : 1); 37 | continue; 38 | int c = a - b; 39 | int x = 0, y = 0, z = 0; 40 | while (a = a >> 1) { 41 | x += a; 42 | } 43 | while (b = b >> 1) { 44 | y += b; 45 | } 46 | while (c = c >> 1) { 47 | z += c; 48 | } 49 | if (x - y > z) printf("0\n"); 50 | else printf("1\n"); 51 | } 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /ACM/poj 3495 Bitwise XOR of Arithmetic Progression.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | Write a program that, given three positive integers x, y and z (x, y, z < 232, x ≤ y), computes the bitwise exclusive disjunction (XOR) of the arithmetic progression x, x + z, x + 2z, …, x + kz, where k is the largest integer such that x + kz ≤ y. 3 | 4 | 输入描述 5 | 6 | The input contains multiple test cases. Each test case consists of three integers x, y, z separated by single spaces on a separate line. There are neither leading or trailing blanks nor empty lines. The input ends once EOF is met. 7 | 8 | 输出描述 9 | 10 | For each test case, output the value of on a separate line. There should be neither leading or trailing spaces nor empty lines. 11 | 12 | 输入例子 13 | ``` 14 | 2 173 11 15 | ``` 16 | 输出例子 17 | ``` 18 | 48 19 | ``` 20 | # 参考答案 21 | ```C++ 22 | #include 23 | #include 24 | #include 25 | #include 26 | using namespace std; 27 | long long x,y,z; 28 | long long Calculate(long long a,long long b,long long c,long long n) 29 | { 30 | if(n==0) return 0; 31 | return (b/c)*n+(a/c)*n*(n-1)/2+Calculate(c,(a*n+b)%c,a%c,(a%c*n+b%c)/c); 32 | } 33 | int main() 34 | { 35 | int i; 36 | while(cin>>x>>y>>z) 37 | { 38 | long long ans=0; 39 | for(i=0;i<32;i++) 40 | ans|=(Calculate(z,x,1ll<Errorr! 5 | 6 | 输入描述 7 | 8 | The input file contains several test cases. Each test case starts with an integer n (0 9. The input data set is correct and ends with an end of file. 9 | 10 | 输出描述 11 | 12 | For each test case find and print the value Dn mod 1000000007. 13 | 14 | 输入例子 15 | 16 | * 2 17 | * 1 2 18 | * 3 19 | * 1 3 9 20 | * 4 21 | * 1 2 3 6 22 | 23 | 24 | 输出例子 25 | * 1 26 | * 12 27 | * 4 28 | 29 | # 参考答案 30 | #include 31 | using namespace std; 32 | 33 | int phi(int n){ 34 | int i,ans=n; 35 | for(i=2;i*i<=n;i++){ 36 | if(n%i==0){ 37 | ans=ans/i*(i-1); 38 | while(n%i==0) n/=i; 39 | } 40 | } 41 | if(n>1) ans=ans/n*(n-1); 42 | return ans; 43 | } 44 | 45 | int main(){ 46 | int n,m; 47 | while(cin>>n){ 48 | long long ans=1; 49 | while(n--){ 50 | cin>>m; 51 | ans*=phi(m); 52 | if(ans>=1000000007) ans%=1000000007; 53 | } 54 | cout< 1 7 | B -> 2 8 | C -> 3 9 | ... 10 | Z -> 26 11 | AA -> 27 12 | AB -> 28 13 | ... 14 |   15 | 示例 1: 16 | 17 | 输入:columnNumber = 1 18 | 输出:"A" 19 | 示例 2: 20 | 21 | 输入:columnNumber = 28 22 | 输出:"AB" 23 | 示例 3: 24 | 25 | 输入:columnNumber = 701 26 | 输出:"ZY" 27 | 示例 4: 28 | 29 | 输入:columnNumber = 2147483647 30 | 输出:"FXSHRXW" 31 |   32 | 提示: 33 | 34 | * 1 <= columnNumber <= 231 - 1 35 | 36 | # 参考答案 37 | ```c++ 38 | class Solution { 39 | public: 40 | string convertToTitle(int columnNumber) { 41 | string ans; 42 | while (columnNumber > 0) { 43 | --columnNumber; 44 | ans += columnNumber % 26 + 'A'; 45 | columnNumber /= 26; 46 | } 47 | reverse(ans.begin(), ans.end()); 48 | return ans; 49 | } 50 | }; 51 | 52 | -------------------------------------------------------------------------------- /leetcode/Excel表列序号.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个Excel表格中的列名称,返回其相应的列序号。 3 | 4 | 例如, 5 | 6 | A -> 1 7 | B -> 2 8 | C -> 3 9 | ... 10 | Z -> 26 11 | AA -> 27 12 | AB -> 28 13 | ... 14 | 示例 1: 15 | 16 | 输入: "A" 17 | 输出: 1 18 | 示例 2: 19 | 20 | 输入: "AB" 21 | 输出: 28 22 | 示例 3: 23 | 24 | 输入: "ZY" 25 | 输出: 701 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | int titleToNumber(string columnTitle) { 32 | int number = 0; 33 | long multiple = 1; 34 | for (int i = columnTitle.size() - 1; i >= 0; i--) { 35 | int k = columnTitle[i] - 'A' + 1; 36 | number += k * multiple; 37 | multiple *= 26; 38 | } 39 | return number; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/Pow(x, n).md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。 3 | 4 | 5 | 示例 1: 6 | 7 | 输入:x = 2.00000, n = 10 8 | 输出:1024.00000 9 | 示例 2: 10 | 11 | 输入:x = 2.10000, n = 3 12 | 输出:9.26100 13 | 示例 3: 14 | 15 | 输入:x = 2.00000, n = -2 16 | 输出:0.25000 17 | 解释:2-2 = 1/2 2 = 1/4 = 0.25 18 |   19 | 20 | 提示: 21 | 22 | * -100.0 < x < 100.0 23 | * -231 <= n <= 231-1 24 | * -104 <= xn <= 104 25 | 26 | 27 | 28 | # 参考答案 29 | ```c++ 30 | class Solution { 31 | public: 32 | double quickMul(double x, long long N) { 33 | if (N == 0) { 34 | return 1.0; 35 | } 36 | double y = quickMul(x, N / 2); 37 | return N % 2 == 0 ? y * y : y * y * x; 38 | } 39 | 40 | double myPow(double x, int n) { 41 | long long N = n; 42 | return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/x 的平方根.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 实现 int sqrt(int x) 函数。 3 | 4 | 计算并返回 x 的平方根,其中 x 是非负整数。 5 | 6 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 7 | 8 | 示例 1: 9 | 10 | 输入: 4 11 | 输出: 2 12 | 示例 2: 13 | 14 | 输入: 8 15 | 输出: 2 16 | 说明: 8 的平方根是 2.82842..., 17 | 由于返回类型是整数,小数部分将被舍去。 18 | 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | int mySqrt(int x) { 24 | if (x == 0) { 25 | return 0; 26 | } 27 | int ans = exp(0.5 * log(x)); 28 | return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /leetcode/三角形最小路径和.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个三角形 triangle ,找出自顶向下的最小路径和。 3 | 4 | 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。 5 | 6 | 示例 1: 7 | 8 | 输入:triangle = [[2],[3,4],[6,5,7],[4,1,8,3]] 9 | 输出:11 10 | 解释:如下面简图所示: 11 | 2 12 | 3 4 13 | 6 5 7 14 | 4 1 8 3 15 | 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 16 | 示例 2: 17 | 18 | 输入:triangle = [[-10]] 19 | 输出:-10 20 |   21 | 22 | 提示: 23 | 24 | * 1 <= triangle.length <= 200 25 | * triangle[0].length == 1 26 | * triangle[i].length == triangle[i - 1].length + 1 27 | * -104 <= triangle[i][j] <= 104 28 | 29 | # 参考答案 30 | ```c++ 31 | class Solution { 32 | public: 33 | int minimumTotal(vector>& triangle) { 34 | int n = triangle.size(); 35 | vector f(n); 36 | f[0] = triangle[0][0]; 37 | for (int i = 1; i < n; ++i) { 38 | f[i] = f[i - 1] + triangle[i][i]; 39 | for (int j = i - 1; j > 0; --j) { 40 | f[j] = min(f[j - 1], f[j]) + triangle[i][j]; 41 | } 42 | f[0] += triangle[i][0]; 43 | } 44 | return *min_element(f.begin(), f.end()); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /leetcode/下一个排列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 4 | 5 | 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 6 | 7 | 必须 原地 修改,只允许使用额外常数空间。 8 | 9 | 10 | 示例 1: 11 | 12 | 输入:nums = [1,2,3] 13 | 输出:[1,3,2] 14 | 示例 2: 15 | 16 | 输入:nums = [3,2,1] 17 | 输出:[1,2,3] 18 | 示例 3: 19 | 20 | 输入:nums = [1,1,5] 21 | 输出:[1,5,1] 22 | 示例 4: 23 | 24 | 输入:nums = [1] 25 | 输出:[1] 26 |   27 | 28 | 提示: 29 | 30 | 1 <= nums.length <= 100 31 | 0 <= nums[i] <= 100 32 | 33 | 34 | # 参考答案 35 | 36 | ```c++ 37 | class Solution { 38 | public: 39 | void nextPermutation(vector& nums) { 40 | int i = nums.size() - 2; 41 | while (i >= 0 && nums[i] >= nums[i + 1]) { 42 | i--; 43 | } 44 | if (i >= 0) { 45 | int j = nums.size() - 1; 46 | while (j >= 0 && nums[i] >= nums[j]) { 47 | j--; 48 | } 49 | swap(nums[i], nums[j]); 50 | } 51 | reverse(nums.begin() + i + 1, nums.end()); 52 | } 53 | }; 54 | 55 | 56 | -------------------------------------------------------------------------------- /leetcode/不同的二叉搜索树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 3 | 4 |   5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125077597-dcbd4b80-e0f3-11eb-8d0b-3b842c458310.png) 9 | 10 | 输入:n = 3 11 | 输出:5 12 | 示例 2: 13 | 14 | 输入:n = 1 15 | 输出:1 16 | 17 | 提示: 18 | 19 | 1 <= n <= 19 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | int numTrees(int n) { 26 | long long C = 1; 27 | for (int i = 0; i < n; ++i) { 28 | C = C * 2 * (2 * i + 1) / (i + 2); 29 | } 30 | return (int)C; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /leetcode/不同路径.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 4 | 5 | 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 6 | 7 | 问总共有多少条不同的路径? 8 | 9 | 示例 1: 10 | 11 | ![image](https://user-images.githubusercontent.com/59190045/125056635-0027cc80-e0db-11eb-9539-4e6bae454943.png) 12 | 13 | 输入:m = 3, n = 7 14 | 输出:28 15 | 示例 2: 16 | 17 | 输入:m = 3, n = 2 18 | 输出:3 19 | 解释: 20 | 从左上角开始,总共有 3 条路径可以到达右下角。 21 | 1. 向右 -> 向下 -> 向下 22 | 2. 向下 -> 向下 -> 向右 23 | 3. 向下 -> 向右 -> 向下 24 | 示例 3: 25 | 26 | 输入:m = 7, n = 3 27 | 输出:28 28 | 示例 4: 29 | 30 | 输入:m = 3, n = 3 31 | 输出:6 32 | 33 | 34 | 提示: 35 | 36 | * 1 <= m, n <= 100 37 | * 题目数据保证答案小于等于 2 * 109 38 | # 参考答案 39 | ```c++ 40 | class Solution { 41 | public: 42 | int uniquePaths(int m, int n) { 43 | vector> f(m, vector(n)); 44 | for (int i = 0; i < m; ++i) { 45 | f[i][0] = 1; 46 | } 47 | for (int j = 0; j < n; ++j) { 48 | f[0][j] = 1; 49 | } 50 | for (int i = 1; i < m; ++i) { 51 | for (int j = 1; j < n; ++j) { 52 | f[i][j] = f[i - 1][j] + f[i][j - 1]; 53 | } 54 | } 55 | return f[m - 1][n - 1]; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /leetcode/两两交换链表中的节点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 3 | 4 | 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125038997-9e5e6700-e0c8-11eb-8e49-331e1864a2e9.png) 9 | 10 | ``` 11 | 输入:head = [1,2,3,4] 12 | 输出:[2,1,4,3] 13 | ``` 14 | 15 | 示例 2: 16 | ``` 17 | 输入:head = [] 18 | 输出:[] 19 | ``` 20 | 示例 3: 21 | ``` 22 | 输入:head = [1] 23 | 输出:[1] 24 |  ``` 25 | 26 | 提示: 27 | 28 | * 链表中节点的数目在范围 [0, 100] 内 29 | * 0 <= Node.val <= 100 30 | 31 | # 参考答案 32 | ```c++ 33 | class Solution { 34 | public: 35 | ListNode* swapPairs(ListNode* head) { 36 | if (head == nullptr || head->next == nullptr) { 37 | return head; 38 | } 39 | ListNode* newHead = head->next; 40 | head->next = swapPairs(newHead->next); 41 | newHead->next = head; 42 | return newHead; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/两数之和 II - 输入有序数组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。 3 | 4 | 函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。 5 | 6 | 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 7 |   8 | 示例 1: 9 | 10 | 输入:numbers = [2,7,11,15], target = 9 11 | 输出:[1,2] 12 | 解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 13 | 示例 2: 14 | 15 | 输入:numbers = [2,3,4], target = 6 16 | 输出:[1,3] 17 | 示例 3: 18 | 19 | 输入:numbers = [-1,0], target = -1 20 | 输出:[1,2] 21 |   22 | 提示: 23 | 24 | * 2 <= numbers.length <= 3 * 104 25 | * -1000 <= numbers[i] <= 1000 26 | * numbers 按 递增顺序 排列 27 | * -1000 <= target <= 1000 28 | * 仅存在一个有效答案 29 | 30 | # 参考答案 31 | ```c++ 32 | class Solution { 33 | public: 34 | vector twoSum(vector& numbers, int target) { 35 | int low = 0, high = numbers.size() - 1; 36 | while (low < high) { 37 | int sum = numbers[low] + numbers[high]; 38 | if (sum == target) { 39 | return {low + 1, high + 1}; 40 | } else if (sum < target) { 41 | ++low; 42 | } else { 43 | --high; 44 | } 45 | } 46 | return {-1, -1}; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /leetcode/两数之和.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 3 | 4 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 5 | 6 | 示例: 7 | 8 | 给定 nums = [2, 7, 11, 15], target = 9 9 | 10 | 因为 nums[0] + nums[1] = 2 + 7 = 9 11 | 所以返回 [0, 1] 12 | 13 | # 参考答案 14 | ```c++ 15 | class Solution { 16 | public: 17 | vector twoSum(vector& A, int target) { 18 | unordered_map m; 19 | for (int i = 0; i < A.size(); ++i) { 20 | int t = target - A[i]; 21 | if (m.count(t)) return { m[t], i }; 22 | m[A[i]] = i; 23 | } 24 | return {}; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /leetcode/两数相加.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 3 | 4 | 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 5 | 6 | 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 7 | 8 | 示例: 9 | 10 | 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 11 | 12 | 输出:7 -> 0 -> 8 13 | 14 | 原因:342 + 465 = 807 15 | 16 | # 参考答案 17 | ```c++ 18 | /** 19 | * Definition for singly-linked list. 20 | * struct ListNode { 21 | * int val; 22 | * ListNode *next; 23 | * ListNode(int x) : val(x), next(NULL) {} 24 | * }; 25 | */ 26 | class Solution { 27 | public: 28 | ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { 29 | ListNode* ret = nullptr; 30 | ListNode* cur = nullptr; 31 | int carry = 0; 32 | while (l1 != nullptr || l2 != nullptr || carry != 0) { 33 | carry += (l1 == nullptr ? 0 : l1->val) + (l2 == nullptr ? 0 : l2->val); 34 | auto temp = new ListNode(carry % 10); 35 | carry /= 10; 36 | if (ret == nullptr) { 37 | ret = temp; 38 | cur = ret; 39 | } 40 | else { 41 | cur->next = temp; 42 | cur = cur->next; 43 | } 44 | l1 = l1 == nullptr ? nullptr : l1->next; 45 | l2 = l2 == nullptr ? nullptr : l2->next; 46 | } 47 | return ret; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /leetcode/串联所有单词的子串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个字符串 s 和一些 长度相同 的单词 words 。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。 3 | 4 | 注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,但不需要考虑 words 中单词串联的顺序。 5 | 6 | 7 | 示例 1: 8 | 9 | 输入:s = "barfoothefoobarman", words = ["foo","bar"] 10 | 输出:[0,9] 11 | 解释: 12 | 从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。 13 | 输出的顺序不重要, [9,0] 也是有效答案。 14 | 示例 2: 15 | 16 | 输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] 17 | 输出:[] 18 | 示例 3: 19 | 20 | 输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"] 21 | 输出:[6,9,12] 22 |   23 | 24 | 提示: 25 | 26 | * 1 <= s.length <= 104 27 | * s 由小写英文字母组成 28 | * 1 <= words.length <= 5000 29 | * 1 <= words[i].length <= 30 30 | * words[i] 由小写英文字母组成 31 | 32 | # 参考答案 33 | ```c++ 34 | class Solution: 35 | def findSubstring(self, s: str, words: List[str]) -> List[int]: 36 | from collections import Counter 37 | if not s or not words:return [] 38 | all_len = sum(map(len, words)) 39 | n = len(s) 40 | words = Counter(words) 41 | res = [] 42 | for i in range(0, n - all_len + 1): 43 | tmp = s[i:i+all_len] 44 | flag = True 45 | for key in words: 46 | if words[key] != tmp.count(key): 47 | flag = False 48 | break 49 | if flag:res.append(i) 50 | return res 51 | -------------------------------------------------------------------------------- /leetcode/乘积最大子数组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 3 | 4 | 示例 1: 5 | 6 | 输入: [2,3,-2,4] 7 | 输出: 6 8 | 解释: 子数组 [2,3] 有最大乘积 6。 9 | 示例 2: 10 | 11 | 输入: [-2,0,-1] 12 | 输出: 0 13 | 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 14 | 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | int maxProduct(vector& nums) { 20 | int maxF = nums[0], minF = nums[0], ans = nums[0]; 21 | for (int i = 1; i < nums.size(); ++i) { 22 | int mx = maxF, mn = minF; 23 | maxF = max(mx * nums[i], max(nums[i], mn * nums[i])); 24 | minF = min(mn * nums[i], min(nums[i], mx * nums[i])); 25 | ans = max(maxF, ans); 26 | } 27 | return ans; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /leetcode/买卖股票的最佳时机 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。 3 | 4 | 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 5 | 6 | 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 7 |   8 | 示例 1: 9 | 10 | 输入: prices = [7,1,5,3,6,4] 11 | 输出: 7 12 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 13 | 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 14 | 示例 2: 15 | 16 | 输入: prices = [1,2,3,4,5] 17 | 输出: 4 18 | 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 19 | 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 20 | 示例 3: 21 | 22 | 输入: prices = [7,6,4,3,1] 23 | 输出: 0 24 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 25 | 26 | 提示: 27 | 28 | * 1 <= prices.length <= 3 * 104 29 | * 0 <= prices[i] <= 104 30 | 31 | # 参考答案 32 | ```c++ 33 | class Solution { 34 | public: 35 | int maxProfit(vector& prices) { 36 | int ans = 0; 37 | int n = prices.size(); 38 | for (int i = 1; i < n; ++i) { 39 | ans += max(0, prices[i] - prices[i - 1]); 40 | } 41 | return ans; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/买卖股票的最佳时机 III.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 3 | 4 | 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 5 | 6 | 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 7 | 8 | 示例 1: 9 | 10 | 输入:prices = [3,3,5,0,0,3,1,4] 11 | 输出:6 12 | 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 13 | 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。 14 | 示例 2: 15 | 16 | 输入:prices = [1,2,3,4,5] 17 | 输出:4 18 | 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   19 | 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   20 | 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 21 | 示例 3: 22 | 23 | 输入:prices = [7,6,4,3,1] 24 | 输出:0 25 | 解释:在这个情况下, 没有交易完成, 所以最大利润为 0。 26 | 示例 4: 27 | 28 | 输入:prices = [1] 29 | 输出:0 30 |   31 | 32 | 提示: 33 | 34 | 1 <= prices.length <= 105 35 | 0 <= prices[i] <= 105 36 | 37 | # 参考答案 38 | ```c++ 39 | class Solution { 40 | public: 41 | int maxProfit(vector& prices) { 42 | int n = prices.size(); 43 | int buy1 = -prices[0], sell1 = 0; 44 | int buy2 = -prices[0], sell2 = 0; 45 | for (int i = 1; i < n; ++i) { 46 | buy1 = max(buy1, -prices[i]); 47 | sell1 = max(sell1, buy1 + prices[i]); 48 | buy2 = max(buy2, sell1 - prices[i]); 49 | sell2 = max(sell2, buy2 + prices[i]); 50 | } 51 | return sell2; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /leetcode/买卖股票的最佳时机.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 3 | 4 | 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 5 | 6 | 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 7 | 8 | 示例 1: 9 | 10 | 输入:[7,1,5,3,6,4] 11 | 输出:5 12 | 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 13 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 14 | 示例 2: 15 | 16 | 输入:prices = [7,6,4,3,1] 17 | 输出:0 18 | 解释:在这种情况下, 没有交易完成, 所以最大利润为 0。 19 |   20 | 21 | 提示: 22 | 23 | * 1 <= prices.length <= 105 24 | * 0 <= prices[i] <= 104 25 | 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | int maxProfit(vector& prices) { 31 | int inf = 1e9; 32 | int minprice = inf, maxprofit = 0; 33 | for (int price: prices) { 34 | maxprofit = max(maxprofit, price - minprice); 35 | minprice = min(price, minprice); 36 | } 37 | return maxprofit; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /leetcode/二叉树展开为链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你二叉树的根结点 root ,请你将它展开为一个单链表: 3 | 4 | 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 5 | 展开后的单链表应该与二叉树 先序遍历 顺序相同。 6 |   7 | 示例 1: 8 | 9 | 输入:root = [1,2,5,3,4,null,6] 10 | 输出:[1,null,2,null,3,null,4,null,5,null,6] 11 | 示例 2: 12 | 13 | 输入:root = [] 14 | 输出:[] 15 | 示例 3: 16 | 17 | 输入:root = [0] 18 | 输出:[0] 19 | 20 | 提示: 21 | 22 | 树中结点数在范围 [0, 2000] 内 23 | -100 <= Node.val <= 100 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | void flatten(TreeNode* root) { 30 | TreeNode *curr = root; 31 | while (curr != nullptr) { 32 | if (curr->left != nullptr) { 33 | auto next = curr->left; 34 | auto predecessor = next; 35 | while (predecessor->right != nullptr) { 36 | predecessor = predecessor->right; 37 | } 38 | predecessor->right = curr->right; 39 | curr->left = nullptr; 40 | curr->right = next; 41 | } 42 | curr = curr->right; 43 | } 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/二叉树的中序遍历.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个二叉树的根节点 root ,返回它的 中序 遍历。 3 |   4 | 示例 1: 5 | 6 | 输入:root = [1,null,2,3] 7 | 输出:[1,3,2] 8 | 示例 2: 9 | 10 | 输入:root = [] 11 | 输出:[] 12 | 示例 3: 13 | 14 | 输入:root = [1] 15 | 输出:[1] 16 | 示例 4: 17 | 18 | 输入:root = [1,2] 19 | 输出:[2,1] 20 | 示例 5: 21 | 22 | 输入:root = [1,null,2] 23 | 输出:[1,2] 24 | 25 | 提示: 26 | 27 | * 树中节点数目在范围 [0, 100] 内 28 | * -100 <= Node.val <= 100 29 | 30 | # 参考答案 31 | ```c++ 32 | class Solution { 33 | public: 34 | vector postorderTraversal(TreeNode* root) { 35 | vector result; 36 | stack st; 37 | if (root != NULL) st.push(root); 38 | while (!st.empty()) { 39 | TreeNode* node = st.top(); 40 | if (node != NULL) { 41 | st.pop(); 42 | st.push(node); // 中 43 | st.push(NULL); 44 | 45 | if (node->right) st.push(node->right); // 右 46 | if (node->left) st.push(node->left); // 左 47 | 48 | } else { 49 | st.pop(); 50 | node = st.top(); 51 | st.pop(); 52 | result.push_back(node->val); 53 | } 54 | } 55 | return result; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /leetcode/二叉树的层序遍历 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 4 | 5 | 例如: 6 | 给定二叉树 [3,9,20,null,null,15,7], 7 | 8 | 3 9 | / \ 10 | 9 20 11 | / \ 12 | 15 7 13 | 返回其自底向上的层序遍历为: 14 | 15 | [ 16 | [15,7], 17 | [9,20], 18 | [3] 19 | ] 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | vector> levelOrderBottom(TreeNode* root) { 25 | auto levelOrder = vector>(); 26 | if (!root) { 27 | return levelOrder; 28 | } 29 | queue q; 30 | q.push(root); 31 | while (!q.empty()) { 32 | auto level = vector(); 33 | int size = q.size(); 34 | for (int i = 0; i < size; ++i) { 35 | auto node = q.front(); 36 | q.pop(); 37 | level.push_back(node->val); 38 | if (node->left) { 39 | q.push(node->left); 40 | } 41 | if (node->right) { 42 | q.push(node->right); 43 | } 44 | } 45 | levelOrder.push_back(level); 46 | } 47 | reverse(levelOrder.begin(), levelOrder.end()); 48 | return levelOrder; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/二叉树的层序遍历.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。 3 | 4 | 示例: 5 | 6 | 二叉树:[3,9,20,null,null,15,7], 7 | 8 | 3 9 | / \ 10 | 9 20 11 | / \ 12 | 15 7 13 | 返回其层序遍历结果: 14 | 15 | [ 16 | [3], 17 | [9,20], 18 | [15,7] 19 | ] 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | vector> levelOrder(TreeNode* root) { 25 | vector > ret; 26 | if (!root) { 27 | return ret; 28 | } 29 | 30 | queue q; 31 | q.push(root); 32 | while (!q.empty()) { 33 | int currentLevelSize = q.size(); 34 | ret.push_back(vector ()); 35 | for (int i = 1; i <= currentLevelSize; ++i) { 36 | auto node = q.front(); q.pop(); 37 | ret.back().push_back(node->val); 38 | if (node->left) q.push(node->left); 39 | if (node->right) q.push(node->right); 40 | } 41 | } 42 | 43 | return ret; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/二叉树的最大深度.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个二叉树,找出其最大深度。 3 | 4 | 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 5 | 6 | 说明: 叶子节点是指没有子节点的节点。 7 | 8 | 示例: 9 | 给定二叉树 [3,9,20,null,null,15,7], 10 | 11 | 3 12 | / \ 13 | 9 20 14 | / \ 15 | 15 7 16 | 返回它的最大深度 3 。 17 | 18 | # 参考答案 19 | ```c++ 20 | class Solution { 21 | public: 22 | int maxDepth(TreeNode* root) { 23 | if (root == nullptr) return 0; 24 | queue Q; 25 | Q.push(root); 26 | int ans = 0; 27 | while (!Q.empty()) { 28 | int sz = Q.size(); 29 | while (sz > 0) { 30 | TreeNode* node = Q.front();Q.pop(); 31 | if (node->left) Q.push(node->left); 32 | if (node->right) Q.push(node->right); 33 | sz -= 1; 34 | } 35 | ans += 1; 36 | } 37 | return ans; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /leetcode/二叉树的最小深度.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个二叉树,找出其最小深度。 3 | 4 | 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 5 | 6 | 说明:叶子节点是指没有子节点的节点。 7 | 8 | 示例 1: 9 | 10 | ![image](https://user-images.githubusercontent.com/59190045/125150739-ca372680-e174-11eb-99ec-17572ce6c803.png) 11 | 12 | 输入:root = [3,9,20,null,null,15,7] 13 | 输出:2 14 | 示例 2: 15 | 16 | 输入:root = [2,null,3,null,4,null,5,null,6] 17 | 输出:5 18 | 19 | 提示: 20 | 21 | 树中节点数的范围在 [0, 105] 内 22 | -1000 <= Node.val <= 1000 23 | 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | int minDepth(TreeNode *root) { 29 | if (root == nullptr) { 30 | return 0; 31 | } 32 | 33 | queue > que; 34 | que.emplace(root, 1); 35 | while (!que.empty()) { 36 | TreeNode *node = que.front().first; 37 | int depth = que.front().second; 38 | que.pop(); 39 | if (node->left == nullptr && node->right == nullptr) { 40 | return depth; 41 | } 42 | if (node->left != nullptr) { 43 | que.emplace(node->left, depth + 1); 44 | } 45 | if (node->right != nullptr) { 46 | que.emplace(node->right, depth + 1); 47 | } 48 | } 49 | 50 | return 0; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /leetcode/二进制求和.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你两个二进制字符串,返回它们的和(用二进制表示)。 3 | 4 | 输入为 非空 字符串且只包含数字 1 和 0。 5 | 6 | 示例 1: 7 | 8 | 输入: a = "11", b = "1" 9 | 输出: "100" 10 | 示例 2: 11 | 12 | 输入: a = "1010", b = "1011" 13 | 输出: "10101" 14 |   15 | 提示: 16 | 17 | * 每个字符串仅由字符 '0' 或 '1' 组成。 18 | * 1 <= a.length, b.length <= 10^4 19 | * 字符串如果不是 "0" ,就都不含前导零。 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | string addBinary(string a, string b) { 26 | string ans; 27 | reverse(a.begin(), a.end()); 28 | reverse(b.begin(), b.end()); 29 | 30 | int n = max(a.size(), b.size()), carry = 0; 31 | for (size_t i = 0; i < n; ++i) { 32 | carry += i < a.size() ? (a.at(i) == '1') : 0; 33 | carry += i < b.size() ? (b.at(i) == '1') : 0; 34 | ans.push_back((carry % 2) ? '1' : '0'); 35 | carry /= 2; 36 | } 37 | 38 | if (carry) { 39 | ans.push_back('1'); 40 | } 41 | reverse(ans.begin(), ans.end()); 42 | 43 | return ans; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/从中序与后序遍历序列构造二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 根据一棵树的中序遍历与后序遍历构造二叉树。 3 | 4 | 注意: 5 | 你可以假设树中没有重复的元素。 6 | 7 | 例如,给出 8 | 9 | 中序遍历 inorder = [9,3,15,20,7] 10 | 后序遍历 postorder = [9,15,7,20,3] 11 | 返回如下的二叉树: 12 | 13 | 3 14 | / \ 15 | 9 20 16 | / \ 17 | 15 7 18 | 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | TreeNode* buildTree(vector& inorder, vector& postorder) { 24 | if (postorder.size() == 0) { 25 | return nullptr; 26 | } 27 | auto root = new TreeNode(postorder[postorder.size() - 1]); 28 | auto s = stack(); 29 | s.push(root); 30 | int inorderIndex = inorder.size() - 1; 31 | for (int i = int(postorder.size()) - 2; i >= 0; i--) { 32 | int postorderVal = postorder[i]; 33 | auto node = s.top(); 34 | if (node->val != inorder[inorderIndex]) { 35 | node->right = new TreeNode(postorderVal); 36 | s.push(node->right); 37 | } else { 38 | while (!s.empty() && s.top()->val == inorder[inorderIndex]) { 39 | node = s.top(); 40 | s.pop(); 41 | inorderIndex--; 42 | } 43 | node->left = new TreeNode(postorderVal); 44 | s.push(node->left); 45 | } 46 | } 47 | return root; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /leetcode/从前序与中序遍历序列构造二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 根据一棵树的前序遍历与中序遍历构造二叉树。 3 | 4 | 注意:
5 | 你可以假设树中没有重复的元素。 6 | 7 | 例如,给出 8 | 9 | 前序遍历 preorder = [3,9,20,15,7]
10 | 中序遍历 inorder = [9,3,15,20,7] 11 | 返回如下的二叉树: 12 | 13 | 3 14 | / \ 15 | 9 20 16 | / \ 17 | 15 7 18 | 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | TreeNode* buildTree(vector& preorder, vector& inorder) { 24 | if (!preorder.size()) { 25 | return nullptr; 26 | } 27 | TreeNode* root = new TreeNode(preorder[0]); 28 | stack stk; 29 | stk.push(root); 30 | int inorderIndex = 0; 31 | for (int i = 1; i < preorder.size(); ++i) { 32 | int preorderVal = preorder[i]; 33 | TreeNode* node = stk.top(); 34 | if (node->val != inorder[inorderIndex]) { 35 | node->left = new TreeNode(preorderVal); 36 | stk.push(node->left); 37 | } 38 | else { 39 | while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) { 40 | node = stk.top(); 41 | stk.pop(); 42 | ++inorderIndex; 43 | } 44 | node->right = new TreeNode(preorderVal); 45 | stk.push(node->right); 46 | } 47 | } 48 | return root; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/位1的个数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。 3 | 4 | 提示: 5 | 6 | * 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 7 | * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 8 | 9 | 示例 1: 10 | 11 | 输入:00000000000000000000000000001011 12 | 输出:3 13 | 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 14 | 示例 2: 15 | 16 | 输入:00000000000000000000000010000000 17 | 输出:1 18 | 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 19 | 示例 3: 20 | 21 | 输入:11111111111111111111111111111101 22 | 输出:31 23 | 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 24 |   25 | 提示: 26 | 27 | 输入必须是长度为 32 的 二进制串 。 28 | 29 | # 参考答案 30 | ```c++ 31 | class Solution { 32 | public: 33 | int hammingWeight(uint32_t n) { 34 | int ret = 0; 35 | while (n) { 36 | n &= n - 1; 37 | ret++; 38 | } 39 | return ret; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/全排列 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 3 | 4 | 示例 1: 5 | 6 | 输入:nums = [1,1,2] 7 | 输出: 8 | [[1,1,2], 9 | [1,2,1], 10 | [2,1,1]] 11 | 示例 2: 12 | 13 | 输入:nums = [1,2,3] 14 | 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 15 |   16 | 提示: 17 | 18 | * 1 <= nums.length <= 8 19 | * -10 <= nums[i] <= 10 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | vector vis; 25 | 26 | public: 27 | void backtrack(vector& nums, vector>& ans, int idx, vector& perm) { 28 | if (idx == nums.size()) { 29 | ans.emplace_back(perm); 30 | return; 31 | } 32 | for (int i = 0; i < (int)nums.size(); ++i) { 33 | if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) { 34 | continue; 35 | } 36 | perm.emplace_back(nums[i]); 37 | vis[i] = 1; 38 | backtrack(nums, ans, idx + 1, perm); 39 | vis[i] = 0; 40 | perm.pop_back(); 41 | } 42 | } 43 | 44 | vector> permuteUnique(vector& nums) { 45 | vector> ans; 46 | vector perm; 47 | vis.resize(nums.size()); 48 | sort(nums.begin(), nums.end()); 49 | backtrack(nums, ans, 0, perm); 50 | return ans; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /leetcode/全排列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 4 | 5 | 示例 1: 6 | 7 | 输入:nums = [1,2,3] 8 | 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 9 | 示例 2: 10 | 11 | 输入:nums = [0,1] 12 | 输出:[[0,1],[1,0]] 13 | 示例 3: 14 | 15 | 输入:nums = [1] 16 | 输出:[[1]] 17 | 18 | 提示: 19 | 20 | * 1 <= nums.length <= 6 21 | * -10 <= nums[i] <= 10 22 | * nums 中的所有整数 互不相同 23 | 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | void backtrack(vector>& res, vector& output, int first, int len){ 29 | // 所有数都填完了 30 | if (first == len) { 31 | res.emplace_back(output); 32 | return; 33 | } 34 | for (int i = first; i < len; ++i) { 35 | // 动态维护数组 36 | swap(output[i], output[first]); 37 | // 继续递归填下一个数 38 | backtrack(res, output, first + 1, len); 39 | // 撤销操作 40 | swap(output[i], output[first]); 41 | } 42 | } 43 | vector> permute(vector& nums) { 44 | vector > res; 45 | backtrack(res, nums, 0, (int)nums.size()); 46 | return res; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /leetcode/分割回文串 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。 3 | 4 | 返回符合要求的 最少分割次数 。 5 | 6 | 示例 1: 7 | 8 | 输入:s = "aab" 9 | 输出:1 10 | 解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。 11 | 示例 2: 12 | 13 | 输入:s = "a" 14 | 输出:0 15 | 示例 3: 16 | 17 | 输入:s = "ab" 18 | 输出:1 19 |   20 | 提示: 21 | 22 | * 1 <= s.length <= 2000 23 | * s 仅由小写英文字母组成 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | int minCut(string s) { 30 | int n = s.size(); 31 | vector> g(n, vector(n, true)); 32 | 33 | for (int i = n - 1; i >= 0; --i) { 34 | for (int j = i + 1; j < n; ++j) { 35 | g[i][j] = (s[i] == s[j]) && g[i + 1][j - 1]; 36 | } 37 | } 38 | 39 | vector f(n, INT_MAX); 40 | for (int i = 0; i < n; ++i) { 41 | if (g[0][i]) { 42 | f[i] = 0; 43 | } 44 | else { 45 | for (int j = 0; j < i; ++j) { 46 | if (g[j + 1][i]) { 47 | f[i] = min(f[i], f[j] + 1); 48 | } 49 | } 50 | } 51 | } 52 | 53 | return f[n - 1]; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /leetcode/分发糖果.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。 3 | 4 | 你需要按照以下要求,帮助老师给这些孩子分发糖果: 5 | 6 | * 每个孩子至少分配到 1 个糖果。 7 | * 评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。 8 | 那么这样下来,老师至少需要准备多少颗糖果呢? 9 | 10 | 示例 1: 11 | 12 | 输入:[1,0,2] 13 | 输出:5 14 | 解释:你可以分别给这三个孩子分发 2、1、2 颗糖果。 15 | 示例 2: 16 | 17 | 输入:[1,2,2] 18 | 输出:4 19 | 解释:你可以分别给这三个孩子分发 1、2、1 颗糖果。 20 | 第三个孩子只得到 1 颗糖果,这已满足上述两个条件。 21 | 22 | # 参考答案 23 | ```c++ 24 | class Solution { 25 | public: 26 | int candy(vector& ratings) { 27 | int n = ratings.size(); 28 | int ret = 1; 29 | int inc = 1, dec = 0, pre = 1; 30 | for (int i = 1; i < n; i++) { 31 | if (ratings[i] >= ratings[i - 1]) { 32 | dec = 0; 33 | pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1; 34 | ret += pre; 35 | inc = pre; 36 | } else { 37 | dec++; 38 | if (dec == inc) { 39 | dec++; 40 | } 41 | ret += dec; 42 | pre = 1; 43 | } 44 | } 45 | return ret; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/分隔链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 3 | 4 | 你应当 保留 两个分区中每个节点的初始相对位置。 5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125074480-e8a70e80-e0ef-11eb-93f6-53a95f7b1daf.png) 9 | 10 | 输入:head = [1,4,3,2,5,2], x = 3 11 | 输出:[1,2,2,4,3,5] 12 | 示例 2: 13 | 14 | 输入:head = [2,1], x = 2 15 | 输出:[1,2] 16 |   17 | 提示: 18 | 19 | * 链表中节点的数目在范围 [0, 200] 内 20 | * -100 <= Node.val <= 100 21 | * -200 <= x <= 200 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | ListNode* partition(ListNode* head, int x) { 28 | ListNode* small = new ListNode(0); 29 | ListNode* smallHead = small; 30 | ListNode* large = new ListNode(0); 31 | ListNode* largeHead = large; 32 | while (head != nullptr) { 33 | if (head->val < x) { 34 | small->next = head; 35 | small = small->next; 36 | } else { 37 | large->next = head; 38 | large = large->next; 39 | } 40 | head = head->next; 41 | } 42 | large->next = nullptr; 43 | small->next = largeHead->next; 44 | return smallHead->next; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /leetcode/删除排序链表中的重复元素 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。 3 | 4 | 返回同样按升序排列的结果链表。 5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125073658-e2646280-e0ee-11eb-8265-36d059aafa7e.png) 9 | 10 | 输入:head = [1,2,3,3,4,4,5] 11 | 输出:[1,2,5] 12 | 示例 2: 13 | 14 | ![image](https://user-images.githubusercontent.com/59190045/125073675-e7c1ad00-e0ee-11eb-81af-a794762f8eff.png) 15 | 16 | 输入:head = [1,1,1,2,3] 17 | 输出:[2,3] 18 | 19 | 提示: 20 | 21 | * 链表中节点数目在范围 [0, 300] 内 22 | * -100 <= Node.val <= 100 23 | * 题目数据保证链表已经按升序排列 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | ListNode* deleteDuplicates(ListNode* head) { 30 | if (!head) { 31 | return head; 32 | } 33 | 34 | ListNode* dummy = new ListNode(0, head); 35 | 36 | ListNode* cur = dummy; 37 | while (cur->next && cur->next->next) { 38 | if (cur->next->val == cur->next->next->val) { 39 | int x = cur->next->val; 40 | while (cur->next && cur->next->val == x) { 41 | cur->next = cur->next->next; 42 | } 43 | } 44 | else { 45 | cur = cur->next; 46 | } 47 | } 48 | 49 | return dummy->next; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /leetcode/删除排序链表中的重复元素.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。 3 | 4 | 返回同样按升序排列的结果链表。 5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125073865-2a838500-e0ef-11eb-882a-141380dc2519.png) 9 | 10 | 输入:head = [1,1,2] 11 | 输出:[1,2] 12 | 示例 2: 13 | 14 | ![image](https://user-images.githubusercontent.com/59190045/125073877-2d7e7580-e0ef-11eb-87e6-39bf41b4f198.png) 15 | 16 | 输入:head = [1,1,2,3,3] 17 | 输出:[1,2,3] 18 |   19 | 20 | 提示: 21 | 22 | * 链表中节点数目在范围 [0, 300] 内 23 | * -100 <= Node.val <= 100 24 | * 题目数据保证链表已经按升序排列 25 | 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | ListNode* deleteDuplicates(ListNode* head) { 31 | if (!head) { 32 | return head; 33 | } 34 | 35 | ListNode* cur = head; 36 | while (cur->next) { 37 | if (cur->val == cur->next->val) { 38 | cur->next = cur->next->next; 39 | } 40 | else { 41 | cur = cur->next; 42 | } 43 | } 44 | 45 | return head; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/删除链表的倒数第 N 个结点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 3 | 4 | 进阶:你能尝试使用一趟扫描实现吗?
5 |   6 | 示例 1:
7 | 8 | ![uploads](https://assets.leetcode.com/uploads/2020/10/03/remove_ex1.jpg) 9 | ``` 10 | 输入:head = [1,2,3,4,5], n = 2 11 | 输出:[1,2,3,5] 12 | ``` 13 | 示例 2: 14 | ``` 15 | 输入:head = [1], n = 1 16 | 输出:[] 17 | ``` 18 | 示例 3: 19 | ``` 20 | 输入:head = [1,2], n = 1 21 | 输出:[1] 22 | ```  23 | 24 | 提示: 25 | 26 | * 链表中结点的数目为 sz 27 | * 1 <= sz <= 30 28 | * 0 <= Node.val <= 100 29 | * 1 <= n <= sz 30 | 31 | # 参考答案 32 | ```c++ 33 | class Solution { 34 | public: 35 | int getLength(ListNode* head) { 36 | int length = 0; 37 | while (head) { 38 | ++length; 39 | head = head->next; 40 | } 41 | return length; 42 | } 43 | 44 | ListNode* removeNthFromEnd(ListNode* head, int n) { 45 | ListNode* dummy = new ListNode(0, head); 46 | int length = getLength(head); 47 | ListNode* cur = dummy; 48 | for (int i = 1; i < length - n + 1; ++i) { 49 | cur = cur->next; 50 | } 51 | cur->next = cur->next->next; 52 | ListNode* ans = dummy->next; 53 | delete dummy; 54 | return ans; 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /leetcode/加一.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 3 | 4 | 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 5 | 6 | 你可以假设除了整数 0 之外,这个整数不会以零开头。 7 | 8 | 示例 1: 9 | 10 | 输入:digits = [1,2,3] 11 | 输出:[1,2,4] 12 | 解释:输入数组表示数字 123。 13 | 示例 2: 14 | 15 | 输入:digits = [4,3,2,1] 16 | 输出:[4,3,2,2] 17 | 解释:输入数组表示数字 4321。 18 | 示例 3: 19 | 20 | 输入:digits = [0] 21 | 输出:[1] 22 |   23 | 提示: 24 | 25 | * 1 <= digits.length <= 100 26 | * 0 <= digits[i] <= 9 27 | 28 | # 参考答案 29 | ```c++ 30 | class Solution { 31 | public: 32 | vector plusOne(vector& digits) { 33 | int carry=(++digits.back())/10;//先计算是否会产生进位 34 | digits.back()%=10;//计算最后一位 35 | int i=digits.size()-2;//从倒数第二位开始 36 | while(i>=0&&carry) 37 | { 38 | digits[i]+=carry; 39 | carry=digits[i]/10; 40 | digits[i]%=10; 41 | --i; 42 | } 43 | if(carry)//最后产生进位的话,需要额外补一个1 44 | digits.insert(digits.begin(),1); 45 | return digits; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/单词拆分.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 3 | 4 | 说明: 5 | 6 | 拆分时可以重复使用字典中的单词。
7 | 你可以假设字典中没有重复的单词。
8 | 示例 1: 9 | 10 | 输入: s = "leetcode", wordDict = ["leet", "code"] 11 | 输出: true 12 | 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。 13 | 示例 2: 14 | 15 | 输入: s = "applepenapple", wordDict = ["apple", "pen"] 16 | 输出: true 17 | 解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。 18 | 注意你可以重复使用字典中的单词。 19 | 示例 3: 20 | 21 | 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 22 | 输出: false 23 | 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | bool wordBreak(string s, vector& wordDict) { 29 | auto wordDictSet = unordered_set (); 30 | for (auto word: wordDict) { 31 | wordDictSet.insert(word); 32 | } 33 | 34 | auto dp = vector (s.size() + 1); 35 | dp[0] = true; 36 | for (int i = 1; i <= s.size(); ++i) { 37 | for (int j = 0; j < i; ++j) { 38 | if (dp[j] && wordDictSet.find(s.substr(j, i - j)) != wordDictSet.end()) { 39 | dp[i] = true; 40 | break; 41 | } 42 | } 43 | } 44 | 45 | return dp[s.size()]; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/反转链表 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。 3 |   4 | 示例 1: 5 | 6 | ![image](https://user-images.githubusercontent.com/59190045/125076422-784dbc80-e0f2-11eb-93ef-e7203e300489.png) 7 | 8 | 输入:head = [1,2,3,4,5], left = 2, right = 4 9 | 输出:[1,4,3,2,5] 10 | 示例 2: 11 | 12 | 输入:head = [5], left = 1, right = 1 13 | 输出:[5] 14 |   15 | 提示: 16 | 17 | * 链表中节点数目为 n 18 | * 1 <= n <= 500 19 | * -500 <= Node.val <= 500 20 | * 1 <= left <= right <= n 21 | 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | ListNode *reverseBetween(ListNode *head, int left, int right) { 28 | // 设置 dummyNode 是这一类问题的一般做法 29 | ListNode *dummyNode = new ListNode(-1); 30 | dummyNode->next = head; 31 | ListNode *pre = dummyNode; 32 | for (int i = 0; i < left - 1; i++) { 33 | pre = pre->next; 34 | } 35 | ListNode *cur = pre->next; 36 | ListNode *next; 37 | for (int i = 0; i < right - left; i++) { 38 | next = cur->next; 39 | cur->next = next->next; 40 | next->next = pre->next; 41 | pre->next = next; 42 | } 43 | return dummyNode->next; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/反转链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 3 |   4 | 5 | 示例 1: 6 | 7 | ![image](https://user-images.githubusercontent.com/59190045/125162008-338c5900-e1b8-11eb-92a1-ae8afdf5ab4e.png) 8 | 9 | 输入:head = [1,2,3,4,5] 10 | 输出:[5,4,3,2,1] 11 | 示例 2: 12 | 13 | ![image](https://user-images.githubusercontent.com/59190045/125162004-2ff8d200-e1b8-11eb-9bd6-b1a614a47fa5.png) 14 | 15 | 输入:head = [1,2] 16 | 输出:[2,1] 17 | 示例 3: 18 | 19 | 输入:head = [] 20 | 输出:[] 21 | 22 | 提示: 23 | 24 | * 链表中节点的数目范围是 [0, 5000] 25 | * -5000 <= Node.val <= 5000 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | ListNode* reverseList(ListNode* head) { 32 | if (!head || !head->next) { 33 | return head; 34 | } 35 | ListNode* newHead = reverseList(head->next); 36 | head->next->next = head; 37 | head->next = nullptr; 38 | return newHead; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /leetcode/只出现一次的数字 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 3 | 4 | 示例 1: 5 | 6 | 输入:nums = [2,2,3,2] 7 | 输出:3 8 | 示例 2: 9 | 10 | 输入:nums = [0,1,0,1,0,1,99] 11 | 输出:99 12 |   13 | 提示: 14 | 15 | * 1 <= nums.length <= 3 * 104 16 | * -231 <= nums[i] <= 231 - 1 17 | * nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 18 | 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | int singleNumber(vector& nums) { 24 | int a = 0, b = 0; 25 | for (int num: nums) { 26 | b = ~a & (b ^ num); 27 | a = ~b & (a ^ num); 28 | } 29 | return b; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /leetcode/只出现一次的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 3 | 4 | 说明: 5 | 6 | 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 7 | 8 | 示例 1: 9 | 10 | 输入: [2,2,1] 11 | 输出: 1 12 | 示例 2: 13 | 14 | 输入: [4,1,2,1,2] 15 | 输出: 4 16 | 17 | # 参考答案 18 | ```c++ 19 | class Solution { 20 | public: 21 | int singleNumber(vector& nums) { 22 | int ret = 0; 23 | for (auto e: nums) ret ^= e; 24 | return ret; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /leetcode/合并两个有序数组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。 3 | 4 | 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。  5 | 6 | 示例 1: 7 | 8 | 输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 9 | 输出:[1,2,2,3,5,6] 10 | 示例 2: 11 | 12 | 输入:nums1 = [1], m = 1, nums2 = [], n = 0 13 | 输出:[1] 14 |   15 | 提示: 16 | 17 | * nums1.length == m + n 18 | * nums2.length == n 19 | * 0 <= m, n <= 200 20 | * 1 <= m + n <= 200 21 | * -109 <= nums1[i], nums2[i] <= 109 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | void merge(vector& nums1, int m, vector& nums2, int n) { 28 | int p1 = m - 1, p2 = n - 1; 29 | int tail = m + n - 1; 30 | int cur; 31 | while (p1 >= 0 || p2 >= 0) { 32 | if (p1 == -1) { 33 | cur = nums2[p2--]; 34 | } else if (p2 == -1) { 35 | cur = nums1[p1--]; 36 | } else if (nums1[p1] > nums2[p2]) { 37 | cur = nums1[p1--]; 38 | } else { 39 | cur = nums2[p2--]; 40 | } 41 | nums1[tail--] = cur; 42 | } 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/合并两个有序链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 3 | 4 | 示例 1: 5 | 6 | ![image](https://user-images.githubusercontent.com/59190045/125038101-94883400-e0c7-11eb-899e-20124cafe9a3.png) 7 | ``` 8 | 输入:l1 = [1,2,4], l2 = [1,3,4] 9 | 输出:[1,1,2,3,4,4] 10 | ``` 11 | 示例 2: 12 | ``` 13 | 输入:l1 = [], l2 = [] 14 | 输出:[] 15 | ``` 16 | 示例 3: 17 | ``` 18 | 输入:l1 = [], l2 = [0] 19 | 输出:[0] 20 |  ``` 21 | 提示: 22 | 23 | * 两个链表的节点数目范围是 [0, 50] 24 | * -100 <= Node.val <= 100 25 | * l1 和 l2 均按 非递减顺序 排列 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { 32 | if (l1 == nullptr) { 33 | return l2; 34 | } else if (l2 == nullptr) { 35 | return l1; 36 | } else if (l1->val < l2->val) { 37 | l1->next = mergeTwoLists(l1->next, l2); 38 | return l1; 39 | } else { 40 | l2->next = mergeTwoLists(l1, l2->next); 41 | return l2; 42 | } 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/合并区间.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [startii4 18 | * intervals[i].length == 2 19 | * 0 <= starti <= endi <= 104 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | vector> merge(vector>& intervals) { 26 | if (intervals.size() == 0) { 27 | return {}; 28 | } 29 | sort(intervals.begin(), intervals.end()); 30 | vector> merged; 31 | for (int i = 0; i < intervals.size(); ++i) { 32 | int L = intervals[i][0], R = intervals[i][1]; 33 | if (!merged.size() || merged.back()[1] < L) { 34 | merged.push_back({L, R}); 35 | } 36 | else { 37 | merged.back()[1] = max(merged.back()[1], R); 38 | } 39 | } 40 | return merged; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /leetcode/同构字符串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定两个字符串 s 和 t,判断它们是否是同构的。 3 | 4 | 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。 5 | 6 | 每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。 7 | 8 | 示例 1: 9 | 10 | 输入:s = "egg", t = "add" 11 | 输出:true 12 | 示例 2: 13 | 14 | 输入:s = "foo", t = "bar" 15 | 输出:false 16 | 示例 3: 17 | 18 | 输入:s = "paper", t = "title" 19 | 输出:true 20 | 21 | 提示: 22 | 23 | 可以假设 s 和 t 长度相同。 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | bool isIsomorphic(string s, string t) { 30 | unordered_map s2t; 31 | unordered_map t2s; 32 | int len = s.length(); 33 | for (int i = 0; i < len; ++i) { 34 | char x = s[i], y = t[i]; 35 | if ((s2t.count(x) && s2t[x] != y) || (t2s.count(y) && t2s[y] != x)) { 36 | return false; 37 | } 38 | s2t[x] = y; 39 | t2s[y] = x; 40 | } 41 | return true; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/地下城游戏.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。 3 | 4 | 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。 5 | 6 | 有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。 7 | 8 | 为了尽快到达公主,骑士决定每次只向右或向下移动一步。 9 |   10 | 11 | 编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。 12 | 13 | 例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。 14 | 15 | -2 (K) | -3 | 3 16 | ------ | -- | - 17 | -5 | -10 | 1 18 | 10 | 30 | -5 (P) 19 | 20 | 说明: 21 | 22 | * 骑士的健康点数没有上限。 23 | * 任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | int calculateMinimumHP(vector>& dungeon) { 30 | int n = dungeon.size(), m = dungeon[0].size(); 31 | vector> dp(n + 1, vector(m + 1, INT_MAX)); 32 | dp[n][m - 1] = dp[n - 1][m] = 1; 33 | for (int i = n - 1; i >= 0; --i) { 34 | for (int j = m - 1; j >= 0; --j) { 35 | int minn = min(dp[i + 1][j], dp[i][j + 1]); 36 | dp[i][j] = max(minn - dungeon[i][j], 1); 37 | } 38 | } 39 | return dp[0][0]; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/多数元素.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 3 | 4 | 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 5 | 6 | 示例 1: 7 | 8 | 输入:[3,2,3] 9 | 输出:3 10 | 示例 2: 11 | 12 | 输入:[2,2,1,1,1,2,2] 13 | 输出:2 14 | 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | int majorityElement(vector& nums) { 20 | int candidate = -1; 21 | int count = 0; 22 | for (int num : nums) { 23 | if (num == candidate) 24 | ++count; 25 | else if (--count < 0) { 26 | candidate = num; 27 | count = 1; 28 | } 29 | } 30 | return candidate; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /leetcode/子集 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。 3 | 4 | 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。  5 | 6 | 示例 1: 7 | 8 | 输入:nums = [1,2,2] 9 | 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]] 10 | 示例 2: 11 | 12 | 输入:nums = [0] 13 | 输出:[[],[0]] 14 | 15 | 提示: 16 | 17 | * 1 <= nums.length <= 10 18 | * -10 <= nums[i] <= 10 19 | 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | vector t; 25 | vector> ans; 26 | 27 | void dfs(bool choosePre, int cur, vector &nums) { 28 | if (cur == nums.size()) { 29 | ans.push_back(t); 30 | return; 31 | } 32 | dfs(false, cur + 1, nums); 33 | if (!choosePre && cur > 0 && nums[cur - 1] == nums[cur]) { 34 | return; 35 | } 36 | t.push_back(nums[cur]); 37 | dfs(true, cur + 1, nums); 38 | t.pop_back(); 39 | } 40 | 41 | vector> subsetsWithDup(vector &nums) { 42 | sort(nums.begin(), nums.end()); 43 | dfs(false, 0, nums); 44 | return ans; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /leetcode/子集.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 4 | 5 | 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 6 | 7 | 示例 1: 8 | 9 | 输入:nums = [1,2,3] 10 | 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 11 | 示例 2: 12 | 13 | 输入:nums = [0] 14 | 输出:[[],[0]] 15 | 16 | 17 | 提示: 18 | 19 | * 1 <= nums.length <= 10 20 | * -10 <= nums[i] <= 10 21 | * nums 中的所有元素 互不相同 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | vector t; 28 | vector> ans; 29 | 30 | void dfs(int cur, vector& nums) { 31 | if (cur == nums.size()) { 32 | ans.push_back(t); 33 | return; 34 | } 35 | t.push_back(nums[cur]); 36 | dfs(cur + 1, nums); 37 | t.pop_back(); 38 | dfs(cur + 1, nums); 39 | } 40 | 41 | vector> subsets(vector& nums) { 42 | dfs(0, nums); 43 | return ans; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/字母异位词分组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 3 | 4 | 示例: 5 | 6 | 输入: ["eat", "tea", "tan", "ate", "nat", "bat"] 7 | 输出: 8 | [ 9 | ["ate","eat","tea"], 10 | ["nat","tan"], 11 | ["bat"] 12 | ] 13 | 说明: 14 | 15 | * 所有输入均为小写字母。 16 | * 不考虑答案输出的顺序。 17 | 18 | # 参考答案 19 | ```c++ 20 | class Solution { 21 | public: 22 | vector> groupAnagrams(vector& strs) { 23 | unordered_map> mp; 24 | for (string& str: strs) { 25 | string key = str; 26 | sort(key.begin(), key.end()); 27 | mp[key].emplace_back(str); 28 | } 29 | vector> ans; 30 | for (auto it = mp.begin(); it != mp.end(); ++it) { 31 | ans.emplace_back(it->second); 32 | } 33 | return ans; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /leetcode/存在重复元素 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。 3 | 4 | 示例 1: 5 | 6 | 输入: nums = [1,2,3,1], k = 3 7 | 输出: true 8 | 示例 2: 9 | 10 | 输入: nums = [1,0,1,1], k = 1 11 | 输出: true 12 | 示例 3: 13 | 14 | 输入: nums = [1,2,3,1,2,3], k = 2 15 | 输出: false 16 | 17 | # 参考答案 18 | ```c++ 19 | class Solution { 20 | public: 21 | bool containsNearbyDuplicate(vector& nums, int k) { 22 | unordered_set existed; 23 | int n = nums.size(); 24 | int curr = 0; 25 | for (int i = 0; i < n; ++i) 26 | { 27 | curr = nums[i]; 28 | if (existed.find(curr) == existed.end()) 29 | { 30 | existed.insert(curr); 31 | if (existed.size() > k) 32 | { 33 | existed.erase(nums[i-k]); 34 | } 35 | } 36 | else 37 | { 38 | return true; 39 | } 40 | } 41 | 42 | return false; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/实现 strStr().md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 实现 strStr() 函数。 3 | 4 | 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回  -1 。 5 | 6 | 7 | 说明: 8 | 9 | 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 10 | 11 | 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。 12 | 13 | 示例 1: 14 | ``` 15 | 输入:haystack = "hello", needle = "ll" 16 | 输出:2 17 | ``` 18 | 示例 2: 19 | ``` 20 | 输入:haystack = "aaaaa", needle = "bba" 21 | 输出:-1 22 | ``` 23 | 示例 3: 24 | ``` 25 | 输入:haystack = "", needle = "" 26 | 输出:0 27 | ``` 28 | 29 | 提示: 30 | 31 | * 0 <= haystack.length, needle.length <= 5 * 104 32 | * haystack 和 needle 仅由小写英文字符组成 33 | 34 | # 参考答案 35 | ```c++ 36 | class Solution { 37 | public: 38 | int strStr(string haystack, string needle) { 39 | int n = haystack.size(), m = needle.size(); 40 | for (int i = 0; i + m <= n; i++) { 41 | bool flag = true; 42 | for (int j = 0; j < m; j++) { 43 | if (haystack[i + j] != needle[j]) { 44 | flag = false; 45 | break; 46 | } 47 | } 48 | if (flag) { 49 | return i; 50 | } 51 | } 52 | return -1; 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /leetcode/对称二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给定一个二叉树,检查它是否是镜像对称的。 4 | 5 | 例如,二叉树 [1,2,2,3,4,4,3] 是对称的。 6 | 7 | 1 8 | / \ 9 | 2 2 10 | / \ / \ 11 | 3 4 4 3 12 | 13 | 14 | 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的: 15 | 16 | 1 17 | / \ 18 | 2 2 19 | \ \ 20 | 3 3 21 | 22 | # 参考答案 23 | ```c++ 24 | class Solution { 25 | public: 26 | bool check(TreeNode *u, TreeNode *v) { 27 | queue q; 28 | q.push(u); q.push(v); 29 | while (!q.empty()) { 30 | u = q.front(); q.pop(); 31 | v = q.front(); q.pop(); 32 | if (!u && !v) continue; 33 | if ((!u || !v) || (u->val != v->val)) return false; 34 | 35 | q.push(u->left); 36 | q.push(v->right); 37 | 38 | q.push(u->right); 39 | q.push(v->left); 40 | } 41 | return true; 42 | } 43 | 44 | bool isSymmetric(TreeNode* root) { 45 | return check(root, root); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/寻找两个正序数组的中位数 .md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ``` 3 | 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。 4 | 5 | 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 6 | 7 | 你可以假设 nums1 和 nums2 不会同时为空。 8 | 9 | 示例 1: 10 | 11 | nums1 = [1, 3] 12 | nums2 = [2] 13 | 14 | 则中位数是 2.0 15 | 示例 2: 16 | 17 | nums1 = [1, 2] 18 | nums2 = [3, 4] 19 | 20 | 则中位数是 (2 + 3)/2 = 2.5 21 | ``` 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | double findMedianSortedArrays(vector& nums1, vector& nums2) { 28 | if (nums1.size() > nums2.size()) swap(nums1, nums2); 29 | int M = nums1.size(), N = nums2.size(), L = 0, R = M, K = (M + N + 1) / 2; 30 | while (true) { 31 | int i = (L + R) / 2, j = K - i; 32 | if (i < M && nums2[j - 1] > nums1[i]) L = i + 1; 33 | else if (i > L && nums1[i - 1] > nums2[j]) R = i - 1; 34 | else { 35 | int maxLeft = max(i ? nums1[i - 1] : INT_MIN, j ? nums2[j - 1] : INT_MIN); 36 | if ((M + N) % 2) return maxLeft; 37 | int minRight = min(i == M ? INT_MAX : nums1[i], j == N ? INT_MAX : nums2[j]); 38 | return (maxLeft + minRight) / 2.0; 39 | } 40 | } 41 | } 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /leetcode/寻找峰值.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 峰值元素是指其值大于左右相邻值的元素。 3 | 4 | 给你一个输入数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。 5 | 6 | 你可以假设 nums[-1] = nums[n] = -∞ 。 7 | 8 | 示例 1: 9 | 10 | 输入:nums = [1,2,3,1] 11 | 输出:2 12 | 解释:3 是峰值元素,你的函数应该返回其索引 2。 13 | 示例 2: 14 | 15 | 输入:nums = [1,2,1,3,5,6,4] 16 | 输出:1 或 5 17 | 解释:你的函数可以返回索引 1,其峰值元素为 2; 18 | 或者返回索引 5, 其峰值元素为 6。 19 | 20 | 提示: 21 | 22 | * 1 <= nums.length <= 1000 23 | * -231 <= nums[i] <= 231 - 1 24 | * 对于所有有效的 i 都有 nums[i] != nums[i + 1] 25 | 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | int findPeakElement(vector& nums) { 31 | int l = 0, r = nums.size() - 1; 32 | while (l < r) { 33 | int mid = l + (r - l) / 2; 34 | if (nums[mid] < nums[mid + 1]) 35 | l = mid + 1; 36 | else r = mid; 37 | } 38 | return l; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /leetcode/寻找旋转排序数组中的最小值 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到: 3 | * 若旋转 4 次,则可以得到 [4,5,6,7,0,1,4] 4 | * 若旋转 7 次,则可以得到 [0,1,4,4,5,6,7] 5 | 注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。 6 | 7 | 给你一个可能存在 重复 元素值的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。 8 | 9 | 示例 1: 10 | 11 | 输入:nums = [1,3,5] 12 | 输出:1 13 | 示例 2: 14 | 15 | 输入:nums = [2,2,2,0,1] 16 | 输出:0 17 |   18 | 提示: 19 | 20 | * n == nums.length 21 | * 1 <= n <= 5000 22 | * -5000 <= nums[i] <= 5000 23 | * nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | int findMin(vector& nums) { 30 | int low = 0; 31 | int high = nums.size() - 1; 32 | while (low < high) { 33 | int pivot = low + (high - low) / 2; 34 | if (nums[pivot] < nums[high]) { 35 | high = pivot; 36 | } 37 | else if (nums[pivot] > nums[high]) { 38 | low = pivot + 1; 39 | } 40 | else { 41 | high -= 1; 42 | } 43 | } 44 | return nums[low]; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /leetcode/寻找旋转排序数组中的最小值.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
3 | 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
4 | 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
5 | 注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
6 | 7 | 给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。 8 | 9 | 示例 1: 10 | 11 | 输入:nums = [3,4,5,1,2] 12 | 输出:1 13 | 解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。 14 | 示例 2: 15 | 16 | 输入:nums = [4,5,6,7,0,1,2] 17 | 输出:0 18 | 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。 19 | 示例 3: 20 | 21 | 输入:nums = [11,13,15,17] 22 | 输出:11 23 | 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。 24 |   25 | 提示: 26 | 27 | * n == nums.length 28 | * 1 <= n <= 5000 29 | * -5000 <= nums[i] <= 5000 30 | * nums 中的所有整数 互不相同 31 | * nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转 32 | 33 | # 参考答案 34 | ```c++ 35 | class Solution { 36 | public: 37 | int findMin(vector& nums) { 38 | int low = 0; 39 | int high = nums.size() - 1; 40 | while (low < high) { 41 | int pivot = low + (high - low) / 2; 42 | if (nums[pivot] < nums[high]) { 43 | high = pivot; 44 | } 45 | else { 46 | low = pivot + 1; 47 | } 48 | } 49 | return nums[low]; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /leetcode/平衡二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个二叉树,判断它是否是高度平衡的二叉树。 3 | 4 | 本题中,一棵高度平衡二叉树定义为: 5 | 6 | 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 7 | 8 | 示例 1: 9 | 10 | ![image](https://user-images.githubusercontent.com/59190045/125150132-e4223a80-e16f-11eb-9153-46c9b2e74261.png) 11 | 12 | 输入:root = [3,9,20,null,null,15,7] 13 | 输出:true 14 | 示例 2: 15 | 16 | ![image](https://user-images.githubusercontent.com/59190045/125150133-e84e5800-e16f-11eb-80ff-2affbcbdc04e.png) 17 | 18 | 输入:root = [1,2,2,3,3,null,null,4,4] 19 | 输出:false 20 | 示例 3: 21 | 22 | 输入:root = [] 23 | 输出:true 24 |   25 | 提示: 26 | 27 | * 树中的节点数在范围 [0, 5000] 内 28 | * -104 <= Node.val <= 104 29 | 30 | # 参考答案 31 | ```c++ 32 | class Solution { 33 | public: 34 | int height(TreeNode* root) { 35 | if (root == NULL) { 36 | return 0; 37 | } 38 | int leftHeight = height(root->left); 39 | int rightHeight = height(root->right); 40 | if (leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight) > 1) { 41 | return -1; 42 | } else { 43 | return max(leftHeight, rightHeight) + 1; 44 | } 45 | } 46 | 47 | bool isBalanced(TreeNode* root) { 48 | return height(root) >= 0; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/快乐数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 编写一个算法来判断一个数 n 是不是快乐数。 3 | 4 | 「快乐数」定义为: 5 | 6 | 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 7 | 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 8 | 如果 可以变为  1,那么这个数就是快乐数。 9 | 如果 n 是快乐数就返回 true ;不是,则返回 false 。 10 | 11 |   12 | 13 | 示例 1: 14 | 15 | 输入:19 16 | 输出:true 17 | 解释:
18 | 12 + 92 = 82
19 | 82 + 22 = 68
20 | 62 + 82 = 100
21 | 12 + 02 + 02 = 1
22 | 23 | 24 | 示例 2: 25 | 26 | 输入:n = 2 27 | 输出:false 28 |   29 | 30 | 提示: 31 | 32 | 1 <= n <= 231 - 1 33 | 34 | # 参考答案 35 | ```c++ 36 | class Solution { 37 | public: 38 | int bitSquareSum(int n) { 39 | int sum = 0; 40 | while(n > 0) 41 | { 42 | int bit = n % 10; 43 | sum += bit * bit; 44 | n = n / 10; 45 | } 46 | return sum; 47 | } 48 | 49 | bool isHappy(int n) { 50 | int slow = n, fast = n; 51 | do{ 52 | slow = bitSquareSum(slow); 53 | fast = bitSquareSum(fast); 54 | fast = bitSquareSum(fast); 55 | }while(slow != fast); 56 | 57 | return slow == 1; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /leetcode/打家劫舍 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。 3 | 4 | 给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。 5 | 6 | 示例 1: 7 | 8 | 输入:nums = [2,3,2] 9 | 输出:3 10 | 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。 11 | 示例 2: 12 | 13 | 输入:nums = [1,2,3,1] 14 | 输出:4 15 | 解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 16 | 偷窃到的最高金额 = 1 + 3 = 4 。 17 | 示例 3: 18 | 19 | 输入:nums = [0] 20 | 输出:0 21 |   22 | 提示: 23 | 24 | * 1 <= nums.length <= 100 25 | * 0 <= nums[i] <= 1000 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | int robRange(vector& nums, int start, int end) { 32 | int first = nums[start], second = max(nums[start], nums[start + 1]); 33 | for (int i = start + 2; i <= end; i++) { 34 | int temp = second; 35 | second = max(first + nums[i], second); 36 | first = temp; 37 | } 38 | return second; 39 | } 40 | 41 | int rob(vector& nums) { 42 | int length = nums.size(); 43 | if (length == 1) { 44 | return nums[0]; 45 | } else if (length == 2) { 46 | return max(nums[0], nums[1]); 47 | } 48 | return max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1)); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/打家劫舍.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 3 | 4 | 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 5 | 6 | 示例 1: 7 | 8 | 输入:[1,2,3,1] 9 | 输出:4 10 | 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 11 | 偷窃到的最高金额 = 1 + 3 = 4 。 12 | 示例 2: 13 | 14 | 输入:[2,7,9,3,1] 15 | 输出:12 16 | 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 17 | 偷窃到的最高金额 = 2 + 9 + 1 = 12 。 18 |   19 | 提示: 20 | 21 | * 1 <= nums.length <= 100 22 | * 0 <= nums[i] <= 400 23 | 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | int rob(vector& nums) { 29 | if (nums.empty()) { 30 | return 0; 31 | } 32 | int size = nums.size(); 33 | if (size == 1) { 34 | return nums[0]; 35 | } 36 | int first = nums[0], second = max(nums[0], nums[1]); 37 | for (int i = 2; i < size; i++) { 38 | int temp = second; 39 | second = max(first + nums[i], second); 40 | first = temp; 41 | } 42 | return second; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/括号生成.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 3 | 4 | 示例 1: 5 | ``` 6 | 输入:n = 3 7 | 输出:["((()))","(()())","(())()","()(())","()()()"] 8 | ``` 9 | 示例 2: 10 | ``` 11 | 输入:n = 1 12 | 输出:["()"] 13 | ``` 14 | 15 | 提示: 16 | 17 | 1 <= n <= 8 18 | 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | vector generateParenthesis(int n) { 24 | vector res; 25 | func(res, "", 0, 0, n); 26 | return res; 27 | } 28 | 29 | void func(vector &res, string str, int l, int r, int n){ 30 | if(l > n || r > n || r > l) return ; 31 | if(l == n && r == n) {res.push_back(str); return;} 32 | func(res, str + '(', l+1, r, n); 33 | func(res, str + ')', l, r+1, n); 34 | return; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /leetcode/排列序列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给出集合 [1,2,3,...,n],其所有元素共有 n! 种排列。 3 | 4 | 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: 5 | 6 | "123" 7 | "132" 8 | "213" 9 | "231" 10 | "312" 11 | "321" 12 | 给定 n 和 k,返回第 k 个排列。 13 | 14 | 示例 1: 15 | 16 | 输入:n = 3, k = 3 17 | 输出:"213" 18 | 示例 2: 19 | 20 | 输入:n = 4, k = 9 21 | 输出:"2314" 22 | 示例 3: 23 | 24 | 输入:n = 3, k = 1 25 | 输出:"123" 26 |   27 | 提示: 28 | 29 | * 1 <= n <= 9 30 | 8 1 <= k <= n! 31 | 32 | # 参考答案 33 | ```c++ 34 | class Solution { 35 | public: 36 | string getPermutation(int n, int k) { 37 | vector factorial(n); 38 | factorial[0] = 1; 39 | for (int i = 1; i < n; ++i) { 40 | factorial[i] = factorial[i - 1] * i; 41 | } 42 | 43 | --k; 44 | string ans; 45 | vector valid(n + 1, 1); 46 | for (int i = 1; i <= n; ++i) { 47 | int order = k / factorial[n - i] + 1; 48 | for (int j = 1; j <= n; ++j) { 49 | order -= valid[j]; 50 | if (!order) { 51 | ans += (j + '0'); 52 | valid[j] = 0; 53 | break; 54 | } 55 | } 56 | k %= factorial[n - i]; 57 | } 58 | return ans; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /leetcode/接雨水.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 3 | 4 | ![image](https://user-images.githubusercontent.com/59190045/125045194-4e36d300-e0cf-11eb-821e-f396cbc640f8.png) 5 | 6 | 示例 1: 7 | 8 | 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 9 | 输出:6 10 | 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 11 | 12 | 示例 2: 13 | 14 | 输入:height = [4,2,0,3,2,5] 15 | 输出:9 16 | 17 | 提示: 18 | 19 | * n == height.length 20 | * 0 <= n <= 3 * 104 21 | * 0 <= height[i] <= 105 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | int trap(vector& height) { 28 | int n = height.size(); 29 | if (n == 0) { 30 | return 0; 31 | } 32 | vector leftMax(n); 33 | leftMax[0] = height[0]; 34 | for (int i = 1; i < n; ++i) { 35 | leftMax[i] = max(leftMax[i - 1], height[i]); 36 | } 37 | 38 | vector rightMax(n); 39 | rightMax[n - 1] = height[n - 1]; 40 | for (int i = n - 2; i >= 0; --i) { 41 | rightMax[i] = max(rightMax[i + 1], height[i]); 42 | } 43 | 44 | int ans = 0; 45 | for (int i = 0; i < n; ++i) { 46 | ans += min(leftMax[i], rightMax[i]) - height[i]; 47 | } 48 | return ans; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/搜索二维矩阵.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: 3 | 4 | 每行中的整数从左到右按升序排列。 5 | 每行的第一个整数大于前一行的最后一个整数。 6 | 7 | 示例 1: 8 | 9 | ![image](https://user-images.githubusercontent.com/59190045/125060432-f56f3680-e0de-11eb-847e-3d6cd0def4c2.png) 10 | 11 | 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3 12 | 输出:true 13 | 示例 2: 14 | 15 | ![image](https://user-images.githubusercontent.com/59190045/125060444-f86a2700-e0de-11eb-87e0-26878a909a5b.png) 16 | 17 | 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13 18 | 输出:false 19 |   20 | 提示: 21 | 22 | m == matrix.length 23 | n == matrix[i].length 24 | 1 <= m, n <= 100 25 | -104 <= matrix[i][j], target <= 104 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | bool searchMatrix(vector> matrix, int target) { 32 | auto row = upper_bound(matrix.begin(), matrix.end(), target, [](const int b, const vector &a) { 33 | return b < a[0]; 34 | }); 35 | if (row == matrix.begin()) { 36 | return false; 37 | } 38 | --row; 39 | return binary_search(row->begin(), row->end(), target); 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/搜索插入位置.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 3 | 4 | 你可以假设数组中无重复元素。 5 | 6 | 示例 1: 7 | 8 | 输入: [1,3,5,6], 5 9 | 输出: 2 10 | 示例 2: 11 | 12 | 输入: [1,3,5,6], 2 13 | 输出: 1 14 | 示例 3: 15 | 16 | 输入: [1,3,5,6], 7 17 | 输出: 4 18 | 示例 4: 19 | 20 | 输入: [1,3,5,6], 0 21 | 输出: 0 22 | 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | int searchInsert(vector& nums, int target) { 28 | int n = nums.size(); 29 | int left = 0, right = n - 1, ans = n; 30 | while (left <= right) { 31 | int mid = ((right - left) >> 1) + left; 32 | if (target <= nums[mid]) { 33 | ans = mid; 34 | right = mid - 1; 35 | } else { 36 | left = mid + 1; 37 | } 38 | } 39 | return ans; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/数字范围按位与.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。 3 | 4 | 示例 1: 5 | 6 | 输入:left = 5, right = 7 7 | 输出:4 8 | 示例 2: 9 | 10 | 输入:left = 0, right = 0 11 | 输出:0 12 | 示例 3: 13 | 14 | 输入:left = 1, right = 2147483647 15 | 输出:0 16 |   17 | 提示: 18 | 19 | 0 <= left <= right <= 231 - 1 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | int rangeBitwiseAnd(int m, int n) { 26 | while (m < n) { 27 | // 抹去最右边的 1 28 | n = n & (n - 1); 29 | } 30 | return n; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /leetcode/整数反转.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。 3 | 4 | 如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。 5 | 6 | 假设环境不允许存储 64 位整数(有符号或无符号)。 7 |   8 | 9 | 示例 1: 10 | ``` 11 | 输入:x = 123 12 | 输出:321 13 | ``` 14 | 示例 2: 15 | ``` 16 | 输入:x = -123 17 | 输出:-321 18 | ``` 19 | 示例 3: 20 | ``` 21 | 输入:x = 120 22 | 输出:21 23 | ``` 24 | 示例 4: 25 | ``` 26 | 输入:x = 0 27 | 输出:0 28 | ``` 29 | 30 | 提示: 31 | 32 | -231 <= x <= 231 - 1 33 | 34 | # 参考答案 35 | ```c++ 36 | #include 37 | 38 | using namespace std; 39 | 40 | class Solution { 41 | public: 42 | int reverse(int x) { 43 | int n = 0; 44 | while (x != 0) { 45 | // Checking the over/underflow. 46 | int r = x % 10; 47 | if (n > INT_MAX / 10 || (n == INT_MAX / 10 && r > 7)) { 48 | return 0; 49 | } 50 | if (n < INT_MIN / 10 || (n == INT_MIN / 10 && r < -8)) { 51 | return 0; 52 | } 53 | 54 | n = n * 10 + r; 55 | x = x / 10; 56 | } 57 | return n; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /leetcode/旋转图像.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 3 | 4 | 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 5 | 6 | 示例 1: 7 | ![image](https://user-images.githubusercontent.com/59190045/125046993-1b8dda00-e0d1-11eb-803f-cfd98e65e88f.png) 8 | 9 | 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 10 | 输出:[[7,4,1],[8,5,2],[9,6,3]] 11 | 12 | 示例 2: 13 | 14 | ![image](https://user-images.githubusercontent.com/59190045/125047045-27799c00-e0d1-11eb-8707-2f499d687da1.png) 15 | 16 | 输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]] 17 | 输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]] 18 | 19 | 示例 3: 20 | 21 | 输入:matrix = [[1]] 22 | 输出:[[1]] 23 | 示例 4: 24 | 25 | 输入:matrix = [[1,2],[3,4]] 26 | 输出:[[3,1],[4,2]] 27 |   28 | 29 | 提示: 30 | 31 | * matrix.length == n 32 | * matrix[i].length == n 33 | * 1 <= n <= 20 34 | * -1000 <= matrix[i][j] <= 1000 35 | 36 | # 参考答案 37 | ```c++ 38 | class Solution { 39 | public: 40 | void rotate(vector>& matrix) { 41 | int n = matrix.size(); 42 | // C++ 这里的 = 拷贝是值拷贝,会得到一个新的数组 43 | auto matrix_new = matrix; 44 | for (int i = 0; i < n; ++i) { 45 | for (int j = 0; j < n; ++j) { 46 | matrix_new[j][n - i - 1] = matrix[i][j]; 47 | } 48 | } 49 | // 这里也是值拷贝 50 | matrix = matrix_new; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /leetcode/旋转数组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 3 | 4 | 示例 1: 5 | 6 | 输入: nums = [1,2,3,4,5,6,7], k = 3 7 | 输出: [5,6,7,1,2,3,4] 8 | 解释: 9 | 向右旋转 1 步: [7,1,2,3,4,5,6] 10 | 向右旋转 2 步: [6,7,1,2,3,4,5] 11 | 向右旋转 3 步: [5,6,7,1,2,3,4] 12 | 示例 2: 13 | 14 | 输入:nums = [-1,-100,3,99], k = 2 15 | 输出:[3,99,-1,-100] 16 | 解释: 17 | 向右旋转 1 步: [99,-1,-100,3] 18 | 向右旋转 2 步: [3,99,-1,-100] 19 |   20 | 21 | 提示: 22 | 23 | * 1 <= nums.length <= 2 * 104 24 | * -231 <= nums[i] <= 231 - 1 25 | * 0 <= k <= 105 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | void reverse(vector& nums, int start, int end) { 32 | while (start < end) { 33 | swap(nums[start], nums[end]); 34 | start += 1; 35 | end -= 1; 36 | } 37 | } 38 | 39 | void rotate(vector& nums, int k) { 40 | k %= nums.size(); 41 | reverse(nums, 0, nums.size() - 1); 42 | reverse(nums, 0, k - 1); 43 | reverse(nums, k, nums.size() - 1); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/旋转链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。 3 | 4 |   5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125056230-9c9d9f00-e0da-11eb-93b8-f6a47544e50f.png) 9 | 10 | 输入:head = [1,2,3,4,5], k = 2 11 | 输出:[4,5,1,2,3] 12 | 示例 2: 13 | 14 | ![image](https://user-images.githubusercontent.com/59190045/125056219-990a1800-e0da-11eb-91dc-d20272bfd9a6.png) 15 | 16 | 输入:head = [0,1,2], k = 4 17 | 输出:[2,0,1] 18 | 19 | 提示: 20 | 21 | * 链表中节点的数目在范围 [0, 500] 内 22 | * -100 <= Node.val <= 100 23 | * 0 <= k <= 2 * 109 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | ListNode* rotateRight(ListNode* head, int k) { 30 | if (k == 0 || head == nullptr || head->next == nullptr) { 31 | return head; 32 | } 33 | int n = 1; 34 | ListNode* iter = head; 35 | while (iter->next != nullptr) { 36 | iter = iter->next; 37 | n++; 38 | } 39 | int add = n - k % n; 40 | if (add == n) { 41 | return head; 42 | } 43 | iter->next = head; 44 | while (add--) { 45 | iter = iter->next; 46 | } 47 | ListNode* ret = iter->next; 48 | iter->next = nullptr; 49 | return ret; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /leetcode/无重复字符的最长子串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ``` 3 | 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 4 | 5 | 示例 1: 6 | 7 | 输入: "abcabcbb" 8 | 输出: 3 9 | 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 10 | 示例 2: 11 | 12 | 输入: "bbbbb" 13 | 输出: 1 14 | 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 15 | 示例 3: 16 | 17 | 输入: "pwwkew" 18 | 输出: 3 19 | 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 20 | 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 21 | ``` 22 | # 参考答案 23 | ```c++ 24 | class Solution { 25 | public: 26 | int lengthOfLongestSubstring(string s) { 27 | 28 | int ans = 0, start = 0; 29 | int n = s.length(); 30 | // 31 | map mp; 32 | 33 | for(int i=0;i4 19 | * s 仅有英文字母和空格 ' ' 组成 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | int lengthOfLastWord(string s) { 26 | int c = 0, i = s.size()-1; 27 | while(i >= 0 && s[i] == ' ') --i; 28 | while(i >= 0 && s[i--] != ' ') ++c; 29 | return c; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /leetcode/最大子序和.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 3 | 4 | 示例 1: 5 | 6 | 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 7 | 输出:6 8 | 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 9 | 示例 2: 10 | 11 | 输入:nums = [1] 12 | 输出:1 13 | 示例 3: 14 | 15 | 输入:nums = [0] 16 | 输出:0 17 | 示例 4: 18 | 19 | 输入:nums = [-1] 20 | 输出:-1 21 | 示例 5: 22 | 23 | 输入:nums = [-100000] 24 | 输出:-100000 25 |   26 | 27 | 提示: 28 | 29 | * 1 <= nums.length <= 3 * 104 30 | * -105 <= nums[i] <= 105 31 | 32 | # 参考答案 33 | ```c++ 34 | class Solution { 35 | public: 36 | int maxSubArray(vector& nums) { 37 | int pre = 0, maxAns = nums[0]; 38 | for (const auto &x: nums) { 39 | pre = max(pre + x, x); 40 | maxAns = max(maxAns, pre); 41 | } 42 | return maxAns; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /leetcode/最小栈.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 3 | 4 | * push(x) —— 将元素 x 推入栈中。 5 | * pop() —— 删除栈顶的元素。 6 | * top() —— 获取栈顶元素。 7 | * getMin() —— 检索栈中的最小元素。 8 |   9 | 10 | 示例: 11 | 12 | 输入: 13 | ["MinStack","push","push","push","getMin","pop","top","getMin"] 14 | [[],[-2],[0],[-3],[],[],[],[]] 15 | 16 | 输出: 17 | [null,null,null,null,-3,null,0,-2] 18 | 19 | 解释: 20 | MinStack minStack = new MinStack(); 21 | minStack.push(-2); 22 | minStack.push(0); 23 | minStack.push(-3); 24 | minStack.getMin(); --> 返回 -3. 25 | minStack.pop(); 26 | minStack.top(); --> 返回 0. 27 | minStack.getMin(); --> 返回 -2. 28 | 29 | 30 | 提示: 31 | 32 | pop、top 和 getMin 操作总是在 非空栈 上调用。 33 | 34 | # 参考答案 35 | ```c++ 36 | class MinStack { 37 | stack x_stack; 38 | stack min_stack; 39 | public: 40 | MinStack() { 41 | min_stack.push(INT_MAX); 42 | } 43 | 44 | void push(int x) { 45 | x_stack.push(x); 46 | min_stack.push(min(min_stack.top(), x)); 47 | } 48 | 49 | void pop() { 50 | x_stack.pop(); 51 | min_stack.pop(); 52 | } 53 | 54 | int top() { 55 | return x_stack.top(); 56 | } 57 | 58 | int getMin() { 59 | return min_stack.top(); 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /leetcode/最短回文串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。 3 | 4 | 示例 1: 5 | 6 | 输入:s = "aacecaaa" 7 | 输出:"aaacecaaa" 8 | 示例 2: 9 | 10 | 输入:s = "abcd" 11 | 输出:"dcbabcd" 12 | 13 | 提示: 14 | 15 | * 0 <= s.length <= 5 * 104 16 | * s 仅由小写英文字母组成 17 | 18 | # 参考答案 19 | ```c++ 20 | class Solution { 21 | public: 22 | string shortestPalindrome(string s) { 23 | int n = s.size(); 24 | vector fail(n, -1); 25 | for (int i = 1; i < n; ++i) { 26 | int j = fail[i - 1]; 27 | while (j != -1 && s[j + 1] != s[i]) { 28 | j = fail[j]; 29 | } 30 | if (s[j + 1] == s[i]) { 31 | fail[i] = j + 1; 32 | } 33 | } 34 | int best = -1; 35 | for (int i = n - 1; i >= 0; --i) { 36 | while (best != -1 && s[best + 1] != s[i]) { 37 | best = fail[best]; 38 | } 39 | if (s[best + 1] == s[i]) { 40 | ++best; 41 | } 42 | } 43 | string add = (best == n - 1 ? "" : s.substr(best + 1, n)); 44 | reverse(add.begin(), add.end()); 45 | return add + s; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/最长公共前缀.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 编写一个函数来查找字符串数组中的最长公共前缀。 3 | 4 | 如果不存在公共前缀,返回空字符串 ""。 5 | 6 | 示例 1: 7 | ``` 8 | 输入:strs = ["flower","flow","flight"] 9 | 输出:"fl" 10 | ``` 11 | 示例 2: 12 | ``` 13 | 输入:strs = ["dog","racecar","car"] 14 | 输出:"" 15 | 解释:输入不存在公共前缀。 16 | ``` 17 | 18 | 提示: 19 | 20 | * 0 <= strs.length <= 200 21 | * 0 <= strs[i].length <= 200 22 | * strs[i] 仅由小写英文字母组成 23 | 24 | # 参考答案 25 | ```c++ 26 | #include 27 | 28 | using namespace std; 29 | 30 | class Solution { 31 | public: 32 | string longestCommonPrefix(vector& strs) { 33 | string lcp; 34 | if (strs.empty()) { 35 | return lcp; 36 | } 37 | for (int j = 0; j < strs[0].length(); j++) { 38 | char c = strs[0][j]; 39 | for (int i = 1; i < strs.size(); i++) { 40 | if (c != strs[i][j]) { 41 | return lcp; 42 | } 43 | } 44 | lcp.push_back(c); 45 | } 46 | return lcp; 47 | } 48 | -------------------------------------------------------------------------------- /leetcode/最长回文子串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个字符串 s,找到 s 中最长的回文子串。 3 | 4 | 示例 1: 5 | ``` 6 | 输入:s = "babad" 7 | 输出:"bab" 8 | 解释:"aba" 同样是符合题意的答案。 9 | ``` 10 | 示例 2: 11 | ``` 12 | 输入:s = "cbbd" 13 | 输出:"bb" 14 | ``` 15 | 示例 3: 16 | ``` 17 | 输入:s = "a" 18 | 输出:"a" 19 | ``` 20 | 示例 4: 21 | ``` 22 | 输入:s = "ac" 23 | 输出:"a" 24 | ``` 25 | 26 | 提示: 27 | 28 | 1 <= s.length <= 1000
29 | s 仅由数字和英文字母(大写和/或小写)组成 30 | 31 | # 参考答案 32 | ```c++ 33 | class Solution { 34 | private: 35 | int expand(string &s, int L, int R) { 36 | while (L >= 0 && R < s.size() && s[L] == s[R]) { 37 | --L; 38 | ++R; 39 | } 40 | return R - L - 1; 41 | } 42 | public: 43 | string longestPalindrome(string s) { 44 | if (s.empty()) return s; 45 | int start = 0, maxLen = 0; 46 | for (int i = 0; i < s.size(); ++i) { 47 | int len1 = expand(s, i, i); 48 | int len2 = expand(s, i, i + 1); 49 | int len = max(len1, len2); 50 | if (len > maxLen) { 51 | start = i - (len - 1) / 2; 52 | maxLen = len; 53 | } 54 | } 55 | return s.substr(start, maxLen); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /leetcode/最长有效括号.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。 3 | 4 | 5 | 示例 1: 6 | 7 | 输入:s = "(()" 8 | 输出:2 9 | 解释:最长有效括号子串是 "()" 10 | 示例 2: 11 | 12 | 输入:s = ")()())" 13 | 输出:4 14 | 解释:最长有效括号子串是 "()()" 15 | 示例 3: 16 | 17 | 输入:s = "" 18 | 输出:0 19 |   20 | 21 | 提示: 22 | 23 | * 0 <= s.length <= 3 * 104 24 | * s[i] 为 '(' 或 ')' 25 | 26 | 27 | # 参考答案 28 | ```c++ 29 | class Solution { 30 | public: 31 | int longestValidParentheses(string s) { 32 | int maxans = 0, n = s.length(); 33 | vector dp(n, 0); 34 | for (int i = 1; i < n; i++) { 35 | if (s[i] == ')') { 36 | if (s[i - 1] == '(') { 37 | dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; 38 | } else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') { 39 | dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; 40 | } 41 | maxans = max(maxans, dp[i]); 42 | } 43 | } 44 | return maxans; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /leetcode/最长连续序列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 3 | 4 | 示例 1: 5 | 6 | 输入:nums = [100,4,200,1,3,2] 7 | 输出:4 8 | 解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。 9 | 示例 2: 10 | 11 | 输入:nums = [0,3,7,2,5,8,4,6,0,1] 12 | 输出:9 13 |   14 | 提示: 15 | 16 | * 0 <= nums.length <= 104 17 | * -109 <= nums[i] <= 109 18 | 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | int longestConsecutive(vector& nums) { 24 | unordered_set num_set; 25 | for (const int& num : nums) { 26 | num_set.insert(num); 27 | } 28 | 29 | int longestStreak = 0; 30 | 31 | for (const int& num : num_set) { 32 | if (!num_set.count(num - 1)) { 33 | int currentNum = num; 34 | int currentStreak = 1; 35 | 36 | while (num_set.count(currentNum + 1)) { 37 | currentNum += 1; 38 | currentStreak += 1; 39 | } 40 | 41 | longestStreak = max(longestStreak, currentStreak); 42 | } 43 | } 44 | 45 | return longestStreak; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /leetcode/有序链表转换二叉搜索树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 3 | 4 | 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 5 | 6 | 示例: 7 | 8 | 给定的有序链表: [-10, -3, 0, 5, 9], 9 | 10 | 一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树: 11 | 12 | 0 13 | / \ 14 | -3 9 15 | / / 16 | -10 5 17 | 18 | # 参考答案 19 | ```c++ 20 | class Solution { 21 | public: 22 | int getLength(ListNode* head) { 23 | int ret = 0; 24 | for (; head != nullptr; ++ret, head = head->next); 25 | return ret; 26 | } 27 | 28 | TreeNode* buildTree(ListNode*& head, int left, int right) { 29 | if (left > right) { 30 | return nullptr; 31 | } 32 | int mid = (left + right + 1) / 2; 33 | TreeNode* root = new TreeNode(); 34 | root->left = buildTree(head, left, mid - 1); 35 | root->val = head->val; 36 | head = head->next; 37 | root->right = buildTree(head, mid + 1, right); 38 | return root; 39 | } 40 | 41 | TreeNode* sortedListToBST(ListNode* head) { 42 | int length = getLength(head); 43 | return buildTree(head, 0, length - 1); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/有效的括号.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 3 | 4 | 有效字符串需满足: 5 | 6 | 左括号必须用相同类型的右括号闭合。
7 | 左括号必须以正确的顺序闭合。 8 |   9 | 10 | 示例 1: 11 | ``` 12 | 输入:s = "()" 13 | 输出:true 14 | ``` 15 | 示例 2: 16 | ``` 17 | 输入:s = "()[]{}" 18 | 输出:true 19 | ``` 20 | 示例 3: 21 | ``` 22 | 输入:s = "(]" 23 | 输出:false 24 | ``` 25 | 示例 4: 26 | ``` 27 | 输入:s = "([)]" 28 | 输出:false 29 | ``` 30 | 示例 5: 31 | ``` 32 | 输入:s = "{[]}" 33 | 输出:true 34 | ``` 35 | 36 | 提示: 37 | 38 | * 1 <= s.length <= 104 39 | * s 仅由括号 '()[]{}' 组成 40 | 41 | # 参考答案 42 | ```c++ 43 | class Solution { 44 | public: 45 | bool isValid(string s) { 46 | int n = s.size(); 47 | if (n % 2 == 1) { 48 | return false; 49 | } 50 | 51 | unordered_map pairs = { 52 | {')', '('}, 53 | {']', '['}, 54 | {'}', '{'} 55 | }; 56 | stack stk; 57 | for (char ch: s) { 58 | if (pairs.count(ch)) { 59 | if (stk.empty() || stk.top() != pairs[ch]) { 60 | return false; 61 | } 62 | stk.pop(); 63 | } 64 | else { 65 | stk.push(ch); 66 | } 67 | } 68 | return stk.empty(); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /leetcode/杨辉三角 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。 3 | 4 | ![image](https://user-images.githubusercontent.com/59190045/125155104-455a0600-e190-11eb-91a7-502d191b7134.png) 5 | 6 | 在杨辉三角中,每个数是它左上方和右上方的数的和。 7 | 8 | 示例: 9 | 10 | 输入: 3 11 | 输出: [1,3,3,1] 12 | 13 | # 参考答案 14 | ```c++ 15 | class Solution { 16 | public: 17 | vector getRow(int rowIndex) { 18 | vector row(rowIndex + 1); 19 | row[0] = 1; 20 | for (int i = 1; i <= rowIndex; ++i) { 21 | row[i] = 1LL * row[i - 1] * (rowIndex - i + 1) / i; 22 | } 23 | return row; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /leetcode/杨辉三角.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 3 | 4 | ![image](https://user-images.githubusercontent.com/59190045/125155193-c74a2f00-e190-11eb-9d9e-52b53aeab4ed.png) 5 | 6 | 在杨辉三角中,每个数是它左上方和右上方的数的和。 7 | 8 | 示例: 9 | 10 | 输入: 5 11 | 输出: 12 | [ 13 | [1], 14 | [1,1], 15 | [1,2,1], 16 | [1,3,3,1], 17 | [1,4,6,4,1] 18 | ] 19 | 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | vector> generate(int numRows) { 25 | vector> ret(numRows); 26 | for (int i = 0; i < numRows; ++i) { 27 | ret[i].resize(i + 1); 28 | ret[i][0] = ret[i][i] = 1; 29 | for (int j = 1; j < i; ++j) { 30 | ret[i][j] = ret[i - 1][j] + ret[i - 1][j - 1]; 31 | } 32 | } 33 | return ret; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /leetcode/柱状图中最大的矩形.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 4 | 5 | 求在该柱状图中,能够勾勒出来的矩形的最大面积。 6 | 7 | ![image](https://user-images.githubusercontent.com/59190045/125074076-6585b880-e0ef-11eb-8a22-381cee619f6b.png) 8 | 9 | 以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。 10 | 11 | ![image](https://user-images.githubusercontent.com/59190045/125074097-6a4a6c80-e0ef-11eb-8bdb-c2878d53fe03.png) 12 | 13 | 图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。 14 | 15 | 示例: 16 | 17 | 输入: [2,1,5,6,2,3] 18 | 输出: 10 19 | # 参考答案 20 | ```c++ 21 | class Solution { 22 | public: 23 | int largestRectangleArea(vector& heights) { 24 | int n = heights.size(); 25 | vector left(n), right(n, n); 26 | 27 | stack mono_stack; 28 | for (int i = 0; i < n; ++i) { 29 | while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) { 30 | right[mono_stack.top()] = i; 31 | mono_stack.pop(); 32 | } 33 | left[i] = (mono_stack.empty() ? -1 : mono_stack.top()); 34 | mono_stack.push(i); 35 | } 36 | 37 | int ans = 0; 38 | for (int i = 0; i < n; ++i) { 39 | ans = max(ans, (right[i] - left[i] - 1) * heights[i]); 40 | } 41 | return ans; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/格雷编码.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。 3 | 4 | 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。即使有多个不同答案,你也只需要返回其中一种。 5 | 6 | 格雷编码序列必须以 0 开头。 7 | 8 | 示例 1: 9 | 10 | 输入: 2 11 | 输出: [0,1,3,2] 12 | 解释: 13 | 00 - 0 14 | 01 - 1 15 | 11 - 3 16 | 10 - 2 17 | 18 | 对于给定的 n,其格雷编码序列并不唯一。 19 | 例如,[0,2,3,1] 也是一个有效的格雷编码序列。 20 | 21 | 00 - 0 22 | 10 - 2 23 | 11 - 3 24 | 01 - 1 25 | 示例 2: 26 | 27 | 输入: 0 28 | 输出: [0] 29 | 解释: 我们定义格雷编码序列必须以 0 开头。 30 |   给定编码总位数为 n 的格雷编码序列,其长度为 2n。当 n = 0 时,长度为 20 = 1。 31 |   因此,当 n = 0 时,其格雷编码序列为 [0]。 32 | 33 | 34 | # 参考答案 35 | ```c++ 36 | class Solution { 37 | public: 38 | vector grayCode(int n) { 39 | vector ans; 40 | int powN = 1 << n; 41 | for(int i = 0; i < powN; ++i) 42 | ans.push_back(i^i>>1); 43 | return ans; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /leetcode/爬楼梯.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 3 | 4 | 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 5 | 6 | 注意:给定 n 是一个正整数。 7 | 8 | 示例 1: 9 | 10 | 输入: 2 11 | 输出: 2 12 | 解释: 有两种方法可以爬到楼顶。 13 | 1. 1 阶 + 1 阶 14 | 2. 2 阶 15 | 示例 2: 16 | 17 | 输入: 3 18 | 输出: 3 19 | 解释: 有三种方法可以爬到楼顶。 20 | 1. 1 阶 + 1 阶 + 1 阶 21 | 2. 1 阶 + 2 阶 22 | 3. 2 阶 + 1 阶 23 | 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | int climbStairs(int n) { 29 | int p = 0, q = 0, r = 1; 30 | for (int i = 1; i <= n; ++i) { 31 | p = q; 32 | q = r; 33 | r = p + q; 34 | } 35 | return r; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /leetcode/移除链表元素.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。  3 | 4 | 示例 1: 5 | 6 | ![image](https://user-images.githubusercontent.com/59190045/125161842-333f8e00-e1b7-11eb-80e9-6ebc3c25cbfd.png) 7 | 8 | 输入:head = [1,2,6,3,4,5,6], val = 6 9 | 输出:[1,2,3,4,5] 10 | 示例 2: 11 | 12 | 输入:head = [], val = 1 13 | 输出:[] 14 | 示例 3: 15 | 16 | 输入:head = [7,7,7,7], val = 7 17 | 输出:[] 18 | 19 | 提示: 20 | 21 | * 列表中的节点数目在范围 [0, 104] 内 22 | * 1 <= Node.val <= 50 23 | * 0 <= val <= 50 24 | 25 | # 参考答案 26 | ```c++ 27 | class Solution { 28 | public: 29 | ListNode* removeElements(ListNode* head, int val) { 30 | struct ListNode* dummyHead = new ListNode(0, head); 31 | struct ListNode* temp = dummyHead; 32 | while (temp->next != NULL) { 33 | if (temp->next->val == val) { 34 | temp->next = temp->next->next; 35 | } else { 36 | temp = temp->next; 37 | } 38 | } 39 | return dummyHead->next; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/第二高的薪水.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。 3 | 4 | +----+--------+ 5 | | Id | Salary | 6 | +----+--------+ 7 | | 1 | 100 | 8 | | 2 | 200 | 9 | | 3 | 300 | 10 | +----+--------+ 11 | 例如上述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。 12 | 13 | +---------------------+ 14 | | SecondHighestSalary | 15 | +---------------------+ 16 | | 200 | 17 | +---------------------+ 18 | 19 | # 参考答案 20 | ``` 21 | SELECT 22 | IFNULL( 23 | (SELECT DISTINCT Salary 24 | FROM Employee 25 | ORDER BY Salary DESC 26 | LIMIT 1 OFFSET 1), 27 | NULL) AS SecondHighestSalary 28 | -------------------------------------------------------------------------------- /leetcode/组合.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 3 | 4 | 示例: 5 | 6 | 输入: n = 4, k = 2 7 | 输出: 8 | [ 9 | [2,4], 10 | [3,4], 11 | [2,3], 12 | [1,2], 13 | [1,3], 14 | [1,4], 15 | ] 16 | 17 | # 参考答案 18 | ```c++ 19 | class Solution { 20 | public: 21 | vector temp; 22 | vector> ans; 23 | 24 | vector> combine(int n, int k) { 25 | // 初始化 26 | // 将 temp 中 [0, k - 1] 每个位置 i 设置为 i + 1,即 [0, k - 1] 存 [1, k] 27 | // 末尾加一位 n + 1 作为哨兵 28 | for (int i = 1; i <= k; ++i) { 29 | temp.push_back(i); 30 | } 31 | temp.push_back(n + 1); 32 | 33 | int j = 0; 34 | while (j < k) { 35 | ans.emplace_back(temp.begin(), temp.begin() + k); 36 | j = 0; 37 | // 寻找第一个 temp[j] + 1 != temp[j + 1] 的位置 t 38 | // 我们需要把 [0, t - 1] 区间内的每个位置重置成 [1, t] 39 | while (j < k && temp[j] + 1 == temp[j + 1]) { 40 | temp[j] = j + 1; 41 | ++j; 42 | } 43 | // j 是第一个 temp[j] + 1 != temp[j + 1] 的位置 44 | ++temp[j]; 45 | } 46 | return ans; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /leetcode/组合两个表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 表1: Person 3 | 4 | +-------------+---------+ 5 | | 列名 | 类型 | 6 | +-------------+---------+ 7 | | PersonId | int | 8 | | FirstName | varchar | 9 | | LastName | varchar | 10 | +-------------+---------+ 11 | PersonId 是上表主键 12 | 表2: Address 13 | 14 | +-------------+---------+ 15 | | 列名 | 类型 | 16 | +-------------+---------+ 17 | | AddressId | int | 18 | | PersonId | int | 19 | | City | varchar | 20 | | State | varchar | 21 | +-------------+---------+ 22 | AddressId 是上表主键 23 |   24 | 25 | 编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息: 26 | 27 | FirstName, LastName, City, State 28 | 29 | # 参考答案 30 | ``` 31 | select FirstName, LastName, City, State 32 | from Person left join Address 33 | on Person.PersonId = Address.PersonId; 34 | -------------------------------------------------------------------------------- /leetcode/组合总和 III.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。 3 | 4 | 说明: 5 | 6 | * 所有数字都是正整数。 7 | * 解集不能包含重复的组合。  8 | 9 | 示例 1: 10 | 11 | 输入: k = 3, n = 7 12 | 输出: [[1,2,4]] 13 | 示例 2: 14 | 15 | 输入: k = 3, n = 9 16 | 输出: [[1,2,6], [1,3,5], [2,3,4]] 17 | 18 | # 参考答案 19 | ```c++ 20 | class Solution { 21 | public: 22 | vector temp; 23 | vector> ans; 24 | 25 | void dfs(int cur, int n, int k, int sum) { 26 | if (temp.size() + (n - cur + 1) < k || temp.size() > k) { 27 | return; 28 | } 29 | if (temp.size() == k && accumulate(temp.begin(), temp.end(), 0) == sum) { 30 | ans.push_back(temp); 31 | return; 32 | } 33 | temp.push_back(cur); 34 | dfs(cur + 1, n, k, sum); 35 | temp.pop_back(); 36 | dfs(cur + 1, n, k, sum); 37 | } 38 | 39 | vector> combinationSum3(int k, int n) { 40 | dfs(1, 9, k, n); 41 | return ans; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/缺失的第一个正数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。 4 | 5 | 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 6 |   7 | 8 | 示例 1: 9 | 10 | 输入:nums = [1,2,0] 11 | 输出:3 12 | 示例 2: 13 | 14 | 输入:nums = [3,4,-1,1] 15 | 输出:2 16 | 示例 3: 17 | 18 | 输入:nums = [7,8,9,11,12] 19 | 输出:1 20 | 21 | 提示: 22 | 23 | 1 <= nums.length <= 5 * 105 24 | -231 <= nums[i] <= 231 - 1 25 | 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | int firstMissingPositive(vector& nums) { 31 | int n = nums.size(); 32 | for (int& num: nums) { 33 | if (num <= 0) { 34 | num = n + 1; 35 | } 36 | } 37 | for (int i = 0; i < n; ++i) { 38 | int num = abs(nums[i]); 39 | if (num <= n) { 40 | nums[num - 1] = -abs(nums[num - 1]); 41 | } 42 | } 43 | for (int i = 0; i < n; ++i) { 44 | if (nums[i] > 0) { 45 | return i + 1; 46 | } 47 | } 48 | return n + 1; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/翻转二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 翻转一棵二叉树。 3 | 4 | 示例: 5 | 6 | 输入: 7 | 8 | 4 9 | / \ 10 | 2 7 11 | / \ / \ 12 | 1 3 6 9 13 | 输出: 14 | 15 | 4 16 | / \ 17 | 7 2 18 | / \ / \ 19 | 9 6 3 1 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | TreeNode* invertTree(TreeNode* root) { 26 | if (root == nullptr) { 27 | return nullptr; 28 | } 29 | TreeNode* left = invertTree(root->left); 30 | TreeNode* right = invertTree(root->right); 31 | root->left = right; 32 | root->right = left; 33 | return root; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /leetcode/螺旋矩阵 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 4 | 5 | 示例 1: 6 | 7 | ![image](https://user-images.githubusercontent.com/59190045/125052181-44649e00-e0d6-11eb-96cd-76ae7c798d1b.png) 8 | 9 | 输入:n = 3 10 | 输出:[[1,2,3],[8,9,4],[7,6,5]] 11 | 示例 2: 12 | 13 | 输入:n = 1 14 | 输出:[[1]] 15 |   16 | 提示: 17 | 18 | 1 <= n <= 20 19 | 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | vector> generateMatrix(int n) { 25 | int maxNum = n * n; 26 | int curNum = 1; 27 | vector> matrix(n, vector(n)); 28 | int row = 0, column = 0; 29 | vector> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右下左上 30 | int directionIndex = 0; 31 | while (curNum <= maxNum) { 32 | matrix[row][column] = curNum; 33 | curNum++; 34 | int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1]; 35 | if (nextRow < 0 || nextRow >= n || nextColumn < 0 || nextColumn >= n || matrix[nextRow][nextColumn] != 0) { 36 | directionIndex = (directionIndex + 1) % 4; // 顺时针旋转至下一个方向 37 | } 38 | row = row + directions[directionIndex][0]; 39 | column = column + directions[directionIndex][1]; 40 | } 41 | return matrix; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/计数质数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 统计所有小于非负整数 n 的质数的数量。 3 | 4 | 示例 1: 5 | 6 | 输入:n = 10 7 | 输出:4 8 | 解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 9 | 示例 2: 10 | 11 | 输入:n = 0 12 | 输出:0 13 | 示例 3: 14 | 15 | 输入:n = 1 16 | 输出:0 17 | 18 | 提示: 19 | 20 | 0 <= n <= 5 * 106 21 | 22 | # 参考答案 23 | ```c++ 24 | class Solution { 25 | public: 26 | int countPrimes(int n) { 27 | vector primes; 28 | vector isPrime(n, 1); 29 | for (int i = 2; i < n; ++i) { 30 | if (isPrime[i]) { 31 | primes.push_back(i); 32 | } 33 | for (int j = 0; j < primes.size() && i * primes[j] < n; ++j) { 34 | isPrime[i * primes[j]] = 0; 35 | if (i % primes[j] == 0) { 36 | break; 37 | } 38 | } 39 | } 40 | return primes.size(); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /leetcode/路径总和.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。 3 | 4 | 叶子节点 是指没有子节点的节点。 5 | 6 | 示例 1: 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/125150800-226e2880-e175-11eb-998c-0e6a76502046.png) 9 | 10 | 输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 11 | 输出:true 12 | 示例 2: 13 | 14 | ![image](https://user-images.githubusercontent.com/59190045/125150808-27cb7300-e175-11eb-94dd-962f081ff1d2.png) 15 | 16 | 输入:root = [1,2,3], targetSum = 5 17 | 输出:false 18 | 示例 3: 19 | 20 | 输入:root = [1,2], targetSum = 0 21 | 输出:false 22 |   23 | 提示: 24 | 25 | * 树中节点的数目在范围 [0, 5000] 内 26 | * -1000 <= Node.val <= 1000 27 | * -1000 <= targetSum <= 1000 28 | 29 | # 参考答案 30 | ```c++ 31 | class Solution { 32 | public: 33 | bool hasPathSum(TreeNode *root, int sum) { 34 | if (root == nullptr) { 35 | return false; 36 | } 37 | if (root->left == nullptr && root->right == nullptr) { 38 | return sum == root->val; 39 | } 40 | return hasPathSum(root->left, sum - root->val) || 41 | hasPathSum(root->right, sum - root->val); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/跳跃游戏 II.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个非负整数数组,你最初位于数组的第一个位置。 3 | 4 | 数组中的每个元素代表你在该位置可以跳跃的最大长度。 5 | 6 | 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 7 | 8 | 假设你总是可以到达数组的最后一个位置。 9 | 10 | 示例 1: 11 | 12 | 输入: [2,3,1,1,4] 13 | 输出: 2 14 | 解释: 跳到最后一个位置的最小跳跃数是 2。 15 | 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 16 | 示例 2: 17 | 18 | 输入: [2,3,0,1,4] 19 | 输出: 2 20 | 21 | 提示: 22 | 23 | * 1 <= nums.length <= 1000 24 | * 0 <= nums[i] <= 105 25 | 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | int jump(vector& nums) { 31 | int maxPos = 0, n = nums.size(), end = 0, step = 0; 32 | for (int i = 0; i < n - 1; ++i) { 33 | if (maxPos >= i) { 34 | maxPos = max(maxPos, i + nums[i]); 35 | if (i == end) { 36 | end = maxPos; 37 | ++step; 38 | } 39 | } 40 | } 41 | return step; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /leetcode/跳跃游戏.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 3 | 4 | 数组中的每个元素代表你在该位置可以跳跃的最大长度。 5 | 6 | 判断你是否能够到达最后一个下标。 7 | 8 | 示例 1: 9 | 10 | 输入:nums = [2,3,1,1,4] 11 | 输出:true 12 | 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。 13 | 示例 2: 14 | 15 | 输入:nums = [3,2,1,0,4] 16 | 输出:false 17 | 解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。 18 |   19 | 提示: 20 | 21 | * 1 <= nums.length <= 3 * 104 22 | * 0 <= nums[i] <= 105 23 | 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | bool canJump(vector& nums) { 29 | int n = nums.size(); 30 | int rightmost = 0; 31 | for (int i = 0; i < n; ++i) { 32 | if (i <= rightmost) { 33 | rightmost = max(rightmost, i + nums[i]); 34 | if (rightmost >= n - 1) { 35 | return true; 36 | } 37 | } 38 | } 39 | return false; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /leetcode/长度最小的子数组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个含有 n 个正整数的数组和一个正整数 target 。 3 | 4 | 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 5 | 6 | 示例 1: 7 | 8 | 输入:target = 7, nums = [2,3,1,2,4,3] 9 | 输出:2 10 | 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 11 | 示例 2: 12 | 13 | 输入:target = 4, nums = [1,4,4] 14 | 输出:1 15 | 示例 3: 16 | 17 | 输入:target = 11, nums = [1,1,1,1,1,1,1,1] 18 | 输出:0 19 | 20 | 提示: 21 | 22 | 1 <= target <= 109 23 | 1 <= nums.length <= 105 24 | 1 <= nums[i] <= 105 25 | 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | int minSubArrayLen(int s, vector& nums) { 31 | int n = nums.size(); 32 | if (n == 0) { 33 | return 0; 34 | } 35 | int ans = INT_MAX; 36 | int start = 0, end = 0; 37 | int sum = 0; 38 | while (end < n) { 39 | sum += nums[end]; 40 | while (sum >= s) { 41 | ans = min(ans, end - start + 1); 42 | sum -= nums[start]; 43 | start++; 44 | } 45 | end++; 46 | } 47 | return ans == INT_MAX ? 0 : ans; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /leetcode/阶乘后的零.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个整数 n,返回 n! 结果尾数中零的数量。 3 | 4 | 示例 1: 5 | 6 | 输入: 3 7 | 输出: 0 8 | 解释: 3! = 6, 尾数中没有零。 9 | 示例 2: 10 | 11 | 输入: 5 12 | 输出: 1 13 | 解释: 5! = 120, 尾数中有 1 个零. 14 | 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | int trailingZeroes(int n) { 20 | // 21 | //计算n/5,n/25,n/125....的结果之和即可,由于怕分母溢出,每次计算之后,先将n/5,然后再重复计算即可(因为是5的倍数) 22 | int ans=0; 23 | while(n>0){ 24 | ans+=n/5; 25 | n=n/5; 26 | } 27 | return ans; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /leetcode/颜色分类.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 3 | 4 | 此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 5 | 6 | 示例 1: 7 | 8 | 输入:nums = [2,0,2,1,1,0] 9 | 输出:[0,0,1,1,2,2] 10 | 示例 2: 11 | 12 | 输入:nums = [2,0,1] 13 | 输出:[0,1,2] 14 | 示例 3: 15 | 16 | 输入:nums = [0] 17 | 输出:[0] 18 | 示例 4: 19 | 20 | 输入:nums = [1] 21 | 输出:[1] 22 |   23 | 24 | 提示: 25 | 26 | * n == nums.length 27 | * 1 <= n <= 300 28 | * nums[i] 为 0、1 或 2 29 | 30 | # 参考答案 31 | ```c++ 32 | class Solution { 33 | public: 34 | void sortColors(vector& nums) { 35 | int n = nums.size(); 36 | int ptr = 0; 37 | for (int i = 0; i < n; ++i) { 38 | if (nums[i] == 0) { 39 | swap(nums[i], nums[ptr]); 40 | ++ptr; 41 | } 42 | } 43 | for (int i = ptr; i < n; ++i) { 44 | if (nums[i] == 1) { 45 | swap(nums[i], nums[ptr]); 46 | ++ptr; 47 | } 48 | } 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /leetcode/验证二叉搜索树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 3 | 4 | 假设一个二叉搜索树具有如下特征: 5 | 6 | * 节点的左子树只包含小于当前节点的数。 7 | * 节点的右子树只包含大于当前节点的数。 8 | * 所有左子树和右子树自身必须也是二叉搜索树。 9 | 10 | 示例 1: 11 | 12 | 输入: 13 | 2 14 | / \ 15 | 1 3 16 | 输出: true 17 | 示例 2: 18 | 19 | 输入: 20 | 5 21 | / \ 22 | 1 4 23 | / \ 24 | 3 6 25 | 输出: false 26 | 解释: 输入为: [5,1,4,null,null,3,6]。 27 | 根节点的值为 5 ,但是其右子节点值为 4 。 28 | 29 | # 参考答案 30 | ```c++ 31 | class Solution { 32 | public: 33 | bool isValidBST(TreeNode* root) { 34 | stack stack; 35 | long long inorder = (long long)INT_MIN - 1; 36 | 37 | while (!stack.empty() || root != nullptr) { 38 | while (root != nullptr) { 39 | stack.push(root); 40 | root = root -> left; 41 | } 42 | root = stack.top(); 43 | stack.pop(); 44 | // 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树 45 | if (root -> val <= inorder) { 46 | return false; 47 | } 48 | inorder = root -> val; 49 | root = root -> right; 50 | } 51 | return true; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /leetcode/验证回文串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 3 | 4 | 说明:本题中,我们将空字符串定义为有效的回文串。 5 | 6 | 示例 1: 7 | 8 | 输入: "A man, a plan, a canal: Panama" 9 | 输出: true 10 | 示例 2: 11 | 12 | 输入: "race a car" 13 | 输出: false 14 | 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | bool isPalindrome(string s) { 20 | int n = s.size(); 21 | int left = 0, right = n - 1; 22 | while (left < right) { 23 | while (left < right && !isalnum(s[left])) { 24 | ++left; 25 | } 26 | while (left < right && !isalnum(s[right])) { 27 | --right; 28 | } 29 | if (left < right) { 30 | if (tolower(s[left]) != tolower(s[right])) { 31 | return false; 32 | } 33 | ++left; 34 | --right; 35 | } 36 | } 37 | return true; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /mysql/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /mysql/MySQL 索引使用有哪些注意事项呢?.md: -------------------------------------------------------------------------------- 1 | # 参考答案 2 | 3 | 可以从三个维度回答这个问题:索引哪些情况会失效,索引不适合哪些场景,索引规则 4 | 5 | ## 索引哪些情况会失效 6 | * 查询条件包含or,可能导致索引失效 7 | * 如何字段类型是字符串,where时一定用引号括起来,否则索引失效 8 | * like通配符可能导致索引失效。 9 | * 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。 10 | * 在索引列上使用mysql的内置函数,索引失效。 11 | * 对索引列运算(如,+、-、*、/),索引失效。 12 | * 索引字段上使用(!= 或者 < >,not in)时,可能会导致索引失效。 13 | * 索引字段上使用is null, is not null,可能导致索引失效。 14 | * 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。 15 | * mysql估计使用全表扫描要比使用索引快,则不使用索引。 16 | ## 索引不适合哪些场景 17 | * 数据量少的不适合加索引 18 | * 更新比较频繁的也不适合加索引 19 | * 区分度低的字段不适合加索引(如性别) 20 | ## 索引的一些潜规则 21 | * 覆盖索引 22 | * 回表 23 | * 索引数据结构(B+树) 24 | * 最左前缀原则 25 | * 索引下推 26 | -------------------------------------------------------------------------------- /mysql/MySQL 遇到过死锁问题吗,你是如何解决的?.md: -------------------------------------------------------------------------------- 1 | # 参考答案 2 | 我排查死锁的一般步骤是酱紫的: 3 | * 查看死锁日志show engine innodb status; 4 | * 找出死锁Sql 5 | * 分析sql加锁情况 6 | * 模拟死锁案发 7 | * 分析死锁日志 8 | * 分析死锁结果 9 | -------------------------------------------------------------------------------- /mysql/日常工作中你是怎么优化SQL的?.md: -------------------------------------------------------------------------------- 1 | # 参考答案 2 | 可以从这几个维度回答这个问题: 3 | * 加索引 4 | * 避免返回不必要的数据 5 | * 适当分批量进行 6 | * 优化sql结构 7 | * 分库分表 8 | * 读写分离 9 | -------------------------------------------------------------------------------- /mysql/说说分库与分表的设计.md: -------------------------------------------------------------------------------- 1 | # 参考答案 2 | 分库分表方案,分库分表中间件,分库分表可能遇到的问题 3 | ## 分库分表方案: 4 | * 水平分库:以字段为依据,按照一定策略(hash、range等),将一个库中的数据拆分到多个库中。 5 | * 水平分表:以字段为依据,按照一定策略(hash、range等),将一个表中的数据拆分到多个表中。 6 | * 垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。 7 | * 垂直分表:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。 8 | ## 常用的分库分表中间件: 9 | * sharding-jdbc(当当) 10 | * Mycat 11 | * TDDL(淘宝) 12 | * Oceanus(58同城数据库中间件) 13 | * vitess(谷歌开发的数据库中间件) 14 | * Atlas(Qihoo 360) 15 | ## 分库分表可能遇到的问题 16 | * 事务问题:需要用分布式事务啦 17 | * 跨节点Join的问题:解决这一问题可以分两次查询实现 18 | * 跨节点的count,order by,group by以及聚合函数问题:分别在各个节点上得到结果后在应用程序端进行合并。 19 | * 数据迁移,容量规划,扩容等问题 20 | * ID问题:数据库被切分后,不能再依赖数据库自身的主键生成机制啦,最简单可以考虑UUID 21 | * 跨分片的排序分页问题(后台加大pagesize处理?) 22 | -------------------------------------------------------------------------------- /nginx/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /redis/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /剑指offer/0到n-1中缺失的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 一个长度为 n−1 的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围 0 到 n−1 之内。 3 | 4 | 在范围 0 到 n−1 的 n 个数字中有且只有一个数字不在该数组中,请找出这个数字。 5 | 6 | 样例 7 | ``` 8 | 输入:[0,1,2,4] 9 | 10 | 输出:3 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | int getMissingNumber(vector& nums) { 17 | if (nums.empty()) return 0; 18 | 19 | int l = 0, r = nums.size() - 1; 20 | while (l < r) 21 | { 22 | int mid = l + r >> 1; 23 | if (nums[mid] != mid) r = mid; 24 | else l = mid + 1; 25 | } 26 | 27 | if (nums[r] == r) r ++ ; 28 | return r; 29 | } 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /剑指offer/1.txt: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /剑指offer/64位整数乘法.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 求 a 乘 b 对 p 取模的值。 3 | 4 | 输入格式
5 | 第一行输入整数a,第二行输入整数b,第三行输入整数p。 6 | 7 | 输出格式
8 | 输出一个整数,表示a*b mod p的值。 9 | 10 | 数据范围
11 | 1≤a,b,p≤1018 12 | 13 | 输入样例: 14 | ``` 15 | 3 16 | 4 17 | 5 18 | ``` 19 | 输出样例: 20 | ``` 21 | 2 22 | ``` 23 | # 参考答案 24 | ```c++ 25 | #include 26 | #include 27 | #define ll long long 28 | using namespace std; 29 | int main() 30 | { 31 | ll a,b,p,res; 32 | cin>>a>>b>>p; 33 | res=0; 34 | while(b) 35 | { 36 | if(b&1) 37 | res=(res+a)%p; 38 | b>>=1; 39 | a=2*a%p; 40 | } 41 | cout< 5 | 三个整数 a,b,p ,在同一行用空格隔开。 6 | 7 | 输出格式
8 | 输出一个整数,表示a^b mod p的值。 9 | 10 | 数据范围
11 | 0≤a,b≤109
12 | 1≤p≤109
13 | 14 | 输入样例: 15 | ``` 16 | 3 2 7 17 | ``` 18 | 输出样例: 19 | ``` 20 | 2 21 | ``` 22 | # 参考答案 23 | ```c++ 24 | #include 25 | using namespace std; 26 | 27 | int main() 28 | { 29 | long long a,b,p,res=1; 30 | scanf("%ld%ld%ld",&a,&b,&p); 31 | while(b) 32 | { 33 | if(b&1) res=res*a%p; 34 | b>>=1;//b右移了一位后,a也需要更新 35 | a=a*a%p; 36 | } 37 | printf("%ld\n",res%p); 38 | } 39 | -------------------------------------------------------------------------------- /剑指offer/不修改数组找出重复的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个长度为 n+1 的数组nums,数组中所有的数均在 1∼n 的范围内,其中 n≥1。 3 | 4 | 请找出数组中任意一个重复的数,但不能修改输入的数组。 5 | 6 | 样例 7 | ``` 8 | 给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。 9 | 10 | 返回 2 或 3。 11 | ``` 12 | 思考题:如果只能使用 O(1) 的额外空间,该怎么做呢? 13 | 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | int duplicateInArray(vector& nums) { 19 | int l = 1, r = nums.size() - 1; 20 | while (l < r) { 21 | int mid = l + r >> 1; // 划分的区间:[l, mid], [mid + 1, r] 22 | int s = 0; 23 | for (auto x : nums) s += x >= l && x <= mid; 24 | if (s > mid - l + 1) r = mid; 25 | else l = mid + 1; 26 | } 27 | return r; 28 | } 29 | }; 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /剑指offer/不分行从上往下打印二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。 3 | 4 | 样例 5 | ``` 6 | 输入如下图所示二叉树[8, 12, 2, null, null, 6, null, 4, null, null, null] 7 | 8 8 | / \ 9 | 12 2 10 | / 11 | 6 12 | / 13 | 4 14 | 15 | 输出:[8, 12, 2, 6, 4] 16 | ``` 17 | # 参考答案 18 | ```c++ 19 | /** 20 | * Definition for a binary tree node. 21 | * struct TreeNode { 22 | * int val; 23 | * TreeNode *left; 24 | * TreeNode *right; 25 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 26 | * }; 27 | */ 28 | class Solution { 29 | public: 30 | vector printFromTopToBottom(TreeNode* root) { 31 | vector res; 32 | if (!root) return res; 33 | queue q; 34 | q.push(root); 35 | 36 | while (q.size()) { 37 | auto t = q.front(); 38 | q.pop(); 39 | res.push_back(t->val); 40 | if (t->left) q.push(t->left); 41 | if (t->right) q.push(t->right); 42 | } 43 | 44 | return res; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /剑指offer/不用加减乘除做加法.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 写一个函数,求两个整数之和,要求在函数体内不得使用 +、-、×、÷ 四则运算符号。 3 | 4 | 样例 5 | ``` 6 | 输入:num1 = 1 , num2 = 2 7 | 8 | 输出:3 9 | ``` 10 | # 参考答案 11 | ```c++ 12 | class Solution { 13 | public: 14 | int add(int num1, int num2){ 15 | while(num2!=0){ 16 | int sum = num1 ^ num2;//不进位的加法 17 | int carry = (num1 & num2)<<1;//进位 18 | num1 = sum; 19 | num2 = carry; 20 | } 21 | return num1; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /剑指offer/丑数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。 3 | 4 | 例如 6、8 都是丑数,但 14 不是,因为它包含质因子 7。 5 | 6 | 求第 n 个丑数的值。 7 | 8 | 样例 9 | ``` 10 | 输入:5 11 | 12 | 输出:5 13 | ``` 14 | 注意:习惯上我们把 1 当做第一个丑数。 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | int getUglyNumber(int n) { 20 | if(n <= 1) return n; 21 | vector f(1,1); 22 | int i = 0, j = 0, k = 0; 23 | long long t = 0; 24 | while(--n) 25 | { 26 | t = min(f[i] * 2, min (f[j] * 3, f[k] * 5)); 27 | if(t == f[i] * 2) i++; 28 | if(t == f[j] * 3) j++; 29 | if(t == f[k] * 5) k++; 30 | f.push_back(t); 31 | } 32 | return f.back(); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /剑指offer/两个链表的第一个公共结点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入两个链表,找出它们的第一个公共结点。 3 | 4 | 当不存在公共节点时,返回空节点。 5 | 6 | 样例 7 | ``` 8 | 给出两个链表如下所示: 9 | A: a1 → a2 10 | ↘ 11 | c1 → c2 → c3 12 | ↗ 13 | B: b1 → b2 → b3 14 | 15 | 输出第一个公共节点c1 16 | ``` 17 | # 参考答案 18 | ```c++ 19 | class Solution { 20 | public: 21 | ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) { 22 | auto p = headA, q = headB; 23 | int la = 0, lb = 0; 24 | for (auto t = headA; t; t = t->next) la ++; 25 | for (auto t = headB; t; t = t->next) lb ++; 26 | int k = la - lb; 27 | if (la < lb) { 28 | p = headB, q = headA; 29 | k = lb - la; 30 | } 31 | while(k --) { 32 | p = p->next; 33 | } 34 | while(p) { 35 | if (p == q) return p; 36 | p = p->next; 37 | q = q->next; 38 | } 39 | return nullptr; 40 | } 41 | }; 42 | 43 | -------------------------------------------------------------------------------- /剑指offer/二叉搜索树与双向链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。 3 | 4 | 要求不能创建任何新的结点,只能调整树中结点指针的指向。 5 | 6 | 注意: 7 | 8 | 需要返回双向链表最左侧的节点。 9 | 10 | 例如,输入下图中左边的二叉搜索树,则输出右边的排序双向链表。 11 | 12 | ![image](https://user-images.githubusercontent.com/59190045/124713991-cec0cc80-df33-11eb-8f9a-a7ab9e758f21.png) 13 | 14 | # 参考答案 15 | ```c++ 16 | /** 17 | * Definition for a binary tree node. 18 | * struct TreeNode { 19 | * int val; 20 | * TreeNode *left; 21 | * TreeNode *right; 22 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 23 | * }; 24 | */ 25 | class Solution { 26 | public: 27 | 28 | TreeNode* pre = NULL; 29 | 30 | TreeNode* convert(TreeNode* root) { 31 | dfs(root); 32 | while(root && root->left) root = root->left; 33 | return root; 34 | } 35 | void dfs(TreeNode* root){ 36 | if(!root) return; 37 | dfs(root->left); 38 | 39 | root->left = pre; 40 | if(pre) pre->right = root; 41 | pre = root; 42 | 43 | dfs(root->right); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /剑指offer/二叉搜索树的后序遍历序列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 3 | 4 | 如果是则返回true,否则返回false。 5 | 6 | 假设输入的数组的任意两个数字都互不相同。 7 | 8 | 样例 9 | ``` 10 | 输入:[4, 8, 6, 12, 16, 14, 10] 11 | 12 | 输出:true 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | vector seq; 19 | 20 | bool verifySequenceOfBST(vector sequence) { 21 | seq = sequence; 22 | return dfs(0, seq.size() - 1); 23 | } 24 | bool dfs(int l, int r) { 25 | if (l >= r) return true; 26 | int root = seq[r]; 27 | int k = l; 28 | while(k < r && seq[k] < root) k ++; 29 | for(int i = k; i < r; i ++) { 30 | if (seq[i] < root) 31 | return false; 32 | } 33 | return dfs(l, k - 1) && dfs(k, r-1); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /剑指offer/二叉搜索树的第k个结点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一棵二叉搜索树,请找出其中的第 k 小的结点。 3 | 4 | 你可以假设树和 k 都存在,并且 1≤k≤ 树的总结点数。 5 | 6 | 样例 7 | ``` 8 | 输入:root = [2, 1, 3, null, null, null, null] ,k = 3 9 | 10 | 2 11 | / \ 12 | 1 3 13 | 14 | 输出:3 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | /** 19 | * Definition for a binary tree node. 20 | * public class TreeNode { 21 | * int val; 22 | * TreeNode left; 23 | * TreeNode right; 24 | * TreeNode(int x) { val = x; } 25 | * } 26 | */ 27 | class Solution { 28 | private TreeNode ans = new TreeNode(-1); 29 | private int a = 0;//值调用的问题,所以要定义全局变量 30 | public TreeNode kthNode(TreeNode root, int k) { 31 | a = k; 32 | dfs(root); 33 | return ans; 34 | } 35 | public void dfs(TreeNode root){ 36 | if(root == null) return; 37 | dfs(root.left); 38 | if(--a == 0) ans = root; 39 | dfs(root.right); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /剑指offer/二叉树中和为某一值的路径.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。 3 | 4 | 从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 5 | 6 | 样例 7 | ``` 8 | 给出二叉树如下所示,并给出num=22。 9 | 5 10 | / \ 11 | 4 6 12 | / / \ 13 | 12 13 6 14 | / \ / \ 15 | 9 1 5 1 16 | 17 | 输出:[[5,4,12,1],[5,6,6,5]] 18 | ``` 19 | # 参考答案 20 | ```c++ 21 | /** 22 | * Definition for a binary tree node. 23 | * public class TreeNode { 24 | * int val; 25 | * TreeNode left; 26 | * TreeNode right; 27 | * TreeNode(int x) { val = x; } 28 | * } 29 | */ 30 | class Solution { 31 | 32 | private static List> ans = new ArrayList<>(); 33 | private static List path = new ArrayList<>(); 34 | 35 | public List> findPath(TreeNode root, int sum) { 36 | 37 | dfs(root, sum); 38 | return ans; 39 | } 40 | 41 | public void dfs(TreeNode root, int sum){ 42 | if(root == null) return; 43 | path.add(root.val); 44 | sum -= root.val; 45 | if(root.left == null && root.right == null && sum == 0){ 46 | //引用调用,需要复制path内容,不然存在ans中的为引用 47 | List tmp = new ArrayList <>(); 48 | tmp.addAll(path); 49 | ans.add(tmp); 50 | 51 | } 52 | dfs(root.left, sum); 53 | dfs(root.right, sum); 54 | path.remove(path.size() - 1); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /剑指offer/二叉树的下一个节点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。 3 | 4 | 注意: 5 | 6 | * 如果给定的节点是中序遍历序列的最后一个,则返回空节点; 7 | * 二叉树一定不为空,且给定的节点一定不是空节点; 8 | 样例 9 | ``` 10 | 假定二叉树是:[2, 1, 3, null, null, null, null], 给出的是值等于2的节点。 11 | 12 | 则应返回值等于3的节点。 13 | 14 | 解释:该二叉树的结构如下,2的后继节点是3。 15 | 2 16 | / \ 17 | 1 3 18 | ``` 19 | # 参考答案 20 | ```c++ 21 | /** 22 | * Definition for a binary tree node. 23 | * struct TreeNode { 24 | * int val; 25 | * TreeNode *left; 26 | * TreeNode *right; 27 | * TreeNode *father; 28 | * TreeNode(int x) : val(x), left(NULL), right(NULL), father(NULL) {} 29 | * }; 30 | */ 31 | class Solution { 32 | public: 33 | TreeNode* inorderSuccessor(TreeNode* p) { 34 | if (p->right) { 35 | p = p->right; 36 | while (p->left) p = p->left; 37 | return p; 38 | } 39 | 40 | while (p->father && p == p->father->right) p = p->father; 41 | return p->father; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /剑指offer/二叉树的深度.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一棵二叉树的根结点,求该树的深度。 3 | 4 | 从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 5 | 6 | 样例 7 | ``` 8 | 输入:二叉树[8, 12, 2, null, null, 6, 4, null, null, null, null]如下图所示: 9 | 8 10 | / \ 11 | 12 2 12 | / \ 13 | 6 4 14 | 15 | 输出:3 16 | ``` 17 | # 参考答案 18 | ```c++ 19 | /** 20 | * Definition for a binary tree node. 21 | * struct TreeNode { 22 | * int val; 23 | * TreeNode *left; 24 | * TreeNode *right; 25 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 26 | * }; 27 | */ 28 | class Solution { 29 | public: 30 | 31 | void dfs(TreeNode* root, int d) { 32 | if (root->left) dfs(root->left, d+1); 33 | if (root->right) dfs(root->right, d+1); 34 | ans = max(ans, d); 35 | } 36 | 37 | int treeDepth(TreeNode* root) { 38 | if (root == NULL) return 0; 39 | ans = 0; 40 | dfs(root, 1); 41 | return ans; 42 | } 43 | private: 44 | int ans; 45 | }; 46 | -------------------------------------------------------------------------------- /剑指offer/二叉树的镜像.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个二叉树,将它变换为它的镜像。 3 | 4 | 样例 5 | ``` 6 | 输入树: 7 | 8 8 | / \ 9 | 6 10 10 | / \ / \ 11 | 5 7 9 11 12 | 13 | [8,6,10,5,7,9,11,null,null,null,null,null,null,null,null] 14 | 输出树: 15 | 8 16 | / \ 17 | 10 6 18 | / \ / \ 19 | 11 9 7 5 20 | 21 | [8,10,6,11,9,7,5,null,null,null,null,null,null,null,null] 22 | ``` 23 | # 参考答案 24 | ```c++ 25 | /** 26 | * Definition for a binary tree node. 27 | * struct TreeNode { 28 | * int val; 29 | * TreeNode *left; 30 | * TreeNode *right; 31 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 32 | * }; 33 | */ 34 | class Solution { 35 | public: 36 | void mirror(TreeNode* root) { 37 | if (!root) return; 38 | swap(root->left, root->right); 39 | mirror(root->left); 40 | mirror(root->right); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /剑指offer/二维数组中的查找.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。 3 | 4 | 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 5 | 6 | 样例 7 | ``` 8 | 输入数组: 9 | 10 | [ 11 | [1,2,8,9], 12 | [2,4,9,12], 13 | [4,7,10,13], 14 | [6,8,11,15] 15 | ] 16 | 17 | 如果输入查找数值为7,则返回true, 18 | 19 | 如果输入查找数值为5,则返回false。 20 | ``` 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | bool searchArray(vector> array, int target) { 26 | if (array.empty() || array[0].empty()) return false; 27 | int i = 0, j = array[0].size() - 1; 28 | while (i < array.size() && j >= 0) { 29 | if (array[i][j] == target) return true; 30 | if (array[i][j] > target) j -- ; 31 | else i ++ ; 32 | } 33 | return false; 34 | } 35 | }; 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /剑指offer/二维费用的背包问题.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ![NO8.png](https://img12.360buyimg.com/ddimg/jfs/t1/185639/11/12585/41956/60e2b6e3Ea66fdd8d/83f4860186f2d787.png) 3 | # 参考答案 4 | ### c++代码 5 | ```c++ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int n, V, M; 11 | const int N = 1e3 + 5; 12 | int v[N], m[N], w[N], f[N][N]; 13 | 14 | signed main () { 15 | cin >> n >> V >> M; 16 | for (int i = 1; i <= n; i ++) { 17 | cin >> v[i] >> m[i] >> w[i];//体积,重量,价值 18 | } 19 | for (int i = 1; i <= n; i ++) 20 | for (int j = V; j >= v[i]; j --) 21 | for (int k = M; k >= m[i]; k --) 22 | f[j][k] = max (f[j - v[i]][k - m[i]] + w[i], f[j][k]);//动态转移方程,01 背包的思路 23 | cout << f[V][M]; 24 | } 25 | 26 | ``` 27 | -------------------------------------------------------------------------------- /剑指offer/二进制中1的个数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个 32 位整数,输出该数二进制表示中 1 的个数。 3 | 4 | 注意: 5 | 6 | 负数在计算机中用其绝对值的补码来表示。 7 | 8 | 样例1 9 | ``` 10 | 输入:9 11 | 输出:2 12 | 解释:9的二进制表示是1001,一共有2个1。 13 | ``` 14 | 样例2 15 | ``` 16 | 输入:-2 17 | 输出:31 18 | 解释:-2在计算机里会被表示成11111111111111111111111111111110, 19 | 一共有31个1。 20 | ``` 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | int NumberOf1(int n) { 26 | int res = 0; 27 | unsigned int un = n; 28 | while (un) res += un & 1, un >>= 1; 29 | return res; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /剑指offer/从1到n整数中1出现的次数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个整数 n,求从 1 到 n 这 n 个整数的十进制表示中 1 出现的次数。 3 | 4 | 例如输入 12,从 1 到 12 这些整数中包含 “1” 的数字有 1,10,11 和 12,其中 “1” 一共出现了 5 次。 5 | 6 | 样例 7 | ``` 8 | 输入: 12 9 | 输出: 5 10 | ``` 11 | # 参考答案 12 | ```c++ 13 | class Solution { 14 | public: 15 | int numberOf1Between1AndN_Solution(int n) { 16 | int count = 0; 17 | for (int i = 1; i <= n; i *= 10) { 18 | int a = n / i,b = n % i; 19 | //之所以补8,是因为当百位为0,则a/10==(a+8)/10, 20 | //当百位>=2,补8会产生进位位,效果等同于(a/10+1) 21 | count += (a + 8) / 10 * i + ((a % 10 == 1) ? b + 1 : 0); 22 | } 23 | return count; 24 | } 25 | }; 26 | //总结一下以上的算法,可以看到,当计算右数第 i 位包含的 X 的个数时: 27 | 28 | //取第 i 位左边(高位)的数字,乘以 10i−1,得到基础值 a。 29 | //取第 i 位数字,计算修正值: 30 | //如果大于 X,则结果为 a+10i−1。 31 | //如果小于 X,则结果为 a。 32 | //如果等 X,则取第 i 位右边(低位)数字,设为 b,最后结果为 a+b+1。 33 | -------------------------------------------------------------------------------- /剑指offer/从尾到头打印链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个链表的头结点,按照 从尾到头 的顺序返回节点的值。 3 | 4 | 返回的结果用数组存储。 5 | 6 | 样例 7 | ``` 8 | 输入:[2, 3, 5] 9 | 返回:[5, 3, 2] 10 | ``` 11 | # 参考答案 12 | ```c++ 13 | /** 14 | * Definition for singly-linked list. 15 | * struct ListNode { 16 | * int val; 17 | * ListNode *next; 18 | * ListNode(int x) : val(x), next(NULL) {} 19 | * }; 20 | */ 21 | class Solution { 22 | public: 23 | vector printListReversingly(ListNode* head) { 24 | vector res; 25 | while (head) { 26 | res.push_back(head->val); 27 | head = head->next; 28 | } 29 | return vector(res.rbegin(), res.rend()); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /剑指offer/分组背包问题.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 有 N 组物品和一个容量是 V 的背包。 3 | 4 | 每组物品有若干个,同一组内的物品最多只能选一个。 5 | 每件物品的体积是Vij,价值是 wij,其中 i 是组号,j 是组内编号。 6 | 7 | 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 8 | 9 | 输出最大价值。 10 | 11 | 输入格式 12 | 第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。 13 | 14 | 接下来有 N 组数据: 15 | 16 | 每组数据第一行有一个整数 Si,表示第 i 个物品组的物品数量; 17 | 每组数据接下来有 Si 行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值; 18 | 输出格式 19 | 输出一个整数,表示最大价值。 20 | 21 | 数据范围 22 | 23 | 0i
≤100 26 | 27 | 0ij,wij≤100 28 | 29 | 输入样例 30 | ``` 31 | 3 5 32 | 2 33 | 1 2 34 | 2 4 35 | 1 36 | 3 4 37 | 1 38 | 4 5 39 | ``` 40 | 输出样例: 41 | ``` 42 | 8 43 | ``` 44 | # 参考答案 45 | ```c++ 46 | #include 47 | using namespace std; 48 | 49 | const int N=110; 50 | int f[N]; 51 | int v[N][N],w[N][N],s[N]; 52 | int n,m,k; 53 | 54 | int main(){ 55 | cin>>n>>m; 56 | for(int i=0;i>s[i]; 58 | for(int j=0;j>v[i][j]>>w[i][j]; 60 | } 61 | } 62 | 63 | for(int i=0;i=0;j--){ 65 | for(int k=0;k=1;k--)也可以 66 | if(j>=v[i][k]) f[j]=max(f[j],f[j-v[i][k]]+w[i][k]); 67 | } 68 | } 69 | } 70 | cout<> printFromTopToBottom(TreeNode* root) { 31 | vector> res; 32 | if(!root) return res; 33 | queue q; 34 | q.push(root); 35 | q.push(NULL); //root层的标识符 36 | 37 | vector cur; 38 | while(q.size()){ 39 | TreeNode* t = q.front(); 40 | q.pop(); 41 | 42 | if(t){ //跟上一道题同样的操作 43 | cur.push_back(t->val); 44 | if(t->left) q.push(t->left); 45 | if(t->right) q.push(t->right); 46 | } 47 | else{ 48 | if(q.size()) q.push(NULL); 49 | res.push_back(cur); 50 | cur.clear(); 51 | } 52 | } 53 | return res; 54 | 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /剑指offer/删除链表中重复的节点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留。 3 | 4 | 样例1 5 | ``` 6 | 输入:1->2->3->3->4->4->5 7 | 8 | 输出:1->2->5 9 | ``` 10 | 样例2 11 | ``` 12 | 输入:1->1->1->2->3 13 | 14 | 输出:2->3 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | /** 19 | * Definition for singly-linked list. 20 | * struct ListNode { 21 | * int val; 22 | * ListNode *next; 23 | * ListNode(int x) : val(x), next(NULL) {} 24 | * }; 25 | */ 26 | class Solution { 27 | public: 28 | ListNode* deleteDuplication(ListNode* head) { 29 | auto dummy = new ListNode(-1); 30 | dummy->next = head; 31 | 32 | auto p = dummy; 33 | while (p->next) { 34 | auto q = p->next; 35 | while (q && p->next->val == q->val) q = q->next; 36 | 37 | if (p->next->next == q) p = p->next; 38 | else p->next = q; 39 | } 40 | 41 | return dummy->next; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /剑指offer/判断该树是不是平衡二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一棵二叉树的根结点,判断该树是不是平衡二叉树。 3 | 4 | 如果某二叉树中任意结点的左右子树的深度相差不超过 1,那么它就是一棵平衡二叉树。 5 | 6 | 注意: 7 | 8 | 规定空树也是一棵平衡二叉树。 9 | 10 | 样例 11 | ``` 12 | 输入:二叉树[5,7,11,null,null,12,9,null,null,null,null]如下所示, 13 | 5 14 | / \ 15 | 7 11 16 | / \ 17 | 12 9 18 | 19 | 输出:true 20 | ``` 21 | # 参考答案 22 | ``c++ 23 | class Solution { 24 | public: 25 | bool isBalanced(TreeNode* root) { 26 | /* 27 | unit test 28 | root is nil 29 | root not nil, left is nil, right is nil 30 | root not nil, left not nil, right nil. 31 | */ 32 | int height=dfs(root); 33 | if(height>=0) return true; 34 | else return false; 35 | } 36 | 37 | // 当非平衡时,return -1; 平衡时,return high; 38 | // 首先判断左子树平衡与否,再判断右子树平衡与否,在判断整棵树平衡与否; 39 | int dfs(TreeNode *root){ 40 | if(!root) return 0; 41 | int left=dfs(root->left); 42 | if(left<0) return -1; 43 | int right=dfs(root->right); 44 | if(right<0) return -1; 45 | if(abs(left-right)>1) return -1; 46 | return max(left,right)+1; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /剑指offer/剪绳子.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给你一根长度为 n 绳子,请把绳子剪成 m 段(m、n 都是整数,2≤n≤58 并且 m≥2)。 3 | 4 | 每段的绳子的长度记为 k[1]、k[2]、……、k[m]。 5 | 6 | k[1]k[2]…k[m] 可能的最大乘积是多少? 7 | 8 | 例如当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到最大的乘积 18。 9 | 10 | 样例 11 | ``` 12 | 输入:8 13 | 14 | 输出:18 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | class Solution { 19 | public: 20 | int integerBreak(int n) { 21 | if (n <= 3) return 1 * (n - 1); 22 | int res = 1; 23 | if (n % 3 == 1) res = 4, n -= 4; 24 | else if (n % 3 == 2) res = 2, n -= 2; 25 | while (n) res *= 3, n -= 3; 26 | return res; 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /剑指offer/包含min函数的栈.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 设计一个支持push,pop,top等操作并且可以在O(1)时间内检索出最小元素的堆栈。 4 | 5 | push(x)–将元素x插入栈中
6 | pop()–移除栈顶元素
7 | top()–得到栈顶元素
8 | getMin()–得到栈中最小元素
9 | 10 | 样例 11 | ``` 12 | MinStack minStack = new MinStack(); 13 | minStack.push(-1); 14 | minStack.push(3); 15 | minStack.push(-4); 16 | minStack.getMin(); --> Returns -4. 17 | minStack.pop(); 18 | minStack.top(); --> Returns 3. 19 | minStack.getMin(); --> Returns -1. 20 | ``` 21 | # 参考答案 22 | ```c++ 23 | class MinStack { 24 | public: 25 | /** initialize your data structure here. */ 26 | stack stackValue; 27 | stack stackMin; 28 | MinStack() { 29 | 30 | } 31 | 32 | void push(int x) { 33 | stackValue.push(x); 34 | if (stackMin.empty() || stackMin.top() >= x) 35 | stackMin.push(x); 36 | } 37 | 38 | void pop() { 39 | if (stackMin.top() == stackValue.top()) stackMin.pop(); 40 | stackValue.pop(); 41 | } 42 | 43 | int top() { 44 | return stackValue.top(); 45 | } 46 | 47 | int getMin() { 48 | return stackMin.top(); 49 | } 50 | }; 51 | 52 | /** 53 | * Your MinStack object will be instantiated and called as such: 54 | * MinStack obj = new MinStack(); 55 | * obj.push(x); 56 | * obj.pop(); 57 | * int param_3 = obj.top(); 58 | * int param_4 = obj.getMin(); 59 | */ 60 | -------------------------------------------------------------------------------- /剑指offer/反转链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。 3 | 4 | 思考题: 5 | 6 | 请同时实现迭代版本和递归版本。 7 | 8 | 样例 9 | ``` 10 | 输入:1->2->3->4->5->NULL 11 | 12 | 输出:5->4->3->2->1->NULL 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | /** 17 | * Definition for singly-linked list. 18 | * struct ListNode { 19 | * int val; 20 | * ListNode *next; 21 | * ListNode(int x) : val(x), next(NULL) {} 22 | * }; 23 | */ 24 | class Solution { 25 | public: 26 | ListNode* reverseList(ListNode* head) { 27 | if (!head || !head->next) return head; 28 | ListNode *tail = reverseList(head->next); 29 | head->next->next = head; 30 | head->next = nullptr; 31 | return tail; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /剑指offer/合并两个排序的链表.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。 3 | 4 | 样例 5 | ``` 6 | 输入:1->3->5 , 2->4->5 7 | 8 | 输出:1->2->3->4->5->5 9 | ``` 10 | # 参考答案 11 | ```c++ 12 | /** 13 | * Definition for singly-linked list. 14 | * struct ListNode { 15 | * int val; 16 | * ListNode *next; 17 | * ListNode(int x) : val(x), next(NULL) {} 18 | * }; 19 | */ 20 | class Solution { 21 | public: 22 | ListNode* merge(ListNode* l1, ListNode* l2) { 23 | ListNode *dummy = new ListNode(0); 24 | ListNode *cur = dummy; 25 | while (l1 != NULL && l2 != NULL) { 26 | if (l1 -> val < l2 -> val) { 27 | cur -> next = l1; 28 | l1 = l1 -> next; 29 | } 30 | else { 31 | cur -> next = l2; 32 | l2 = l2 -> next; 33 | } 34 | cur = cur -> next; 35 | } 36 | cur -> next = (l1 != NULL ? l1 : l2); 37 | return dummy -> next; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /剑指offer/和为S的两个数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个数组和一个数字 s,在数组中查找两个数,使得它们的和正好是 s。 3 | 4 | 如果有多对数字的和等于 s,输出任意一对即可。 5 | 6 | 你可以认为每组输入中都至少含有一组满足条件的输出。 7 | 8 | 样例 9 | ``` 10 | 输入:[1,2,3,4] , sum=7 11 | 12 | 输出:[3,4] 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | vector findNumbersWithSum(vector& nums, int target) 19 | { 20 | unordered_map hash;//创建哈希表 21 | for (int i = 0; i < nums.size(); ++i) { 22 | if(hash[target - nums[i]] == 0)//如果哈希表中没有target - nums[i] 23 | hash[nums[i]]++;//nums[i]出现次数加1 24 | else//如果哈希表中有target - nums[i] 25 | return {nums[i], target - nums[i]};//返回答案 26 | } 27 | return {}; 28 | 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /剑指offer/和为S的连续正数序列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个正数 S,打印出所有和为 S 的连续正数序列(至少含有两个数)。 3 | 4 | 例如输入 15,由于 1+2+3+4+5=4+5+6=7+8=15,所以结果打印出 3 个连续序列 1∼5、4∼6 和 7∼8。 5 | 6 | 样例 7 | ``` 8 | 输入:15 9 | 10 | 输出:[[1,2,3,4,5],[4,5,6],[7,8]] 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | vector > findContinuousSequence(int sum) { 17 | vector> res; 18 | vector path; 19 | for(int i = 1, j = 2; j < sum && i < j; j) { 20 | int ans = (i + j) * (j - i + 1) / 2; 21 | if ( ans == sum){//如果相同就加入。 22 | int k = i; 23 | while(k <= j) 24 | path.push_back(k++); 25 | res.push_back(path); 26 | path.clear(); 27 | i ++, j ++;//两个指针同时往后移。 28 | } 29 | else if ( ans < sum) {//如果比较小,j就往后移动。 30 | j ++; 31 | } 32 | else 33 | i ++;//否则i往后移动 34 | } 35 | return res; 36 | 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /剑指offer/圆圈中最后剩下的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 0,1,…,n−1 这 n 个数字 (n>0) 排成一个圆圈,从数字 0 开始每次从这个圆圈里删除第 m 个数字。 3 | 4 | 求出这个圆圈里剩下的最后一个数字。 5 | 6 | 样例 7 | ``` 8 | 输入:n=5 , m=3 9 | 10 | 输出:3 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | #include 15 | class Solution { 16 | public: 17 | int lastRemaining(int n, int m){ 18 | list nums; 19 | for (int i = 0; i < n; ++i) nums.push_back(i); 20 | auto it = nums.begin(); 21 | int k = m - 1; 22 | while (nums.size() > 1){ 23 | while (k--){ 24 | it++; 25 | if (it == nums.end()) it = nums.begin();//别迭代器移到开头实现模拟环形列表 26 | } 27 | it = nums.erase(it);//删除第m个元素 28 | if (it == nums.end()) it = nums.begin(); 29 | k = m - 1; 30 | } 31 | return nums.front(); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /剑指offer/在O(1)时间删除链表结点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定单向链表的一个节点指针,定义一个函数在O(1)时间删除该结点。 3 | 4 | 假设链表一定存在,并且该节点一定不是尾节点。 5 | 6 | 样例 7 | ``` 8 | 输入:链表 1->4->6->8 9 | 删掉节点:第2个节点即6(头节点为第0个节点) 10 | 11 | 输出:新链表 1->4->8 12 | ``` 13 | # 参考答案 14 | ```c++ 15 | /** 16 | * Definition for singly-linked list. 17 | * struct ListNode { 18 | * int val; 19 | * ListNode *next; 20 | * ListNode(int x) : val(x), next(NULL) {} 21 | * }; 22 | */ 23 | class Solution { 24 | public: 25 | void deleteNode(ListNode* node) { 26 | 27 | auto p = node->next; 28 | 29 | node->val = p->val; 30 | node->next = p->next; 31 | // 这两步的作用就是将 *(node->next) 赋值给 *node,所以可以合并成一条语句: 32 | // *node = *(node->next); 33 | 34 | delete p; 35 | } 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /剑指offer/增减序列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。 3 | 4 | 求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。 5 | 6 | 输入格式
7 | 第一行输入正整数 n。 8 | 9 | 接下来 n 行,每行输入一个整数,第 i+1 行的整数代表 ai。 10 | 11 | 输出格式
12 | 第一行输出最少操作次数。 13 | 14 | 第二行输出最终能得到多少种结果。 15 | 16 | 数据范围
17 | 05,
18 | 0≤ai<2147483648 19 | 20 | 输入样例: 21 | ``` 22 | 4 23 | 1 24 | 1 25 | 2 26 | 2 27 | ``` 28 | 输出样例: 29 | ``` 30 | 1 31 | 2 32 | ``` 33 | # 参考答案 34 | ```c++ 35 | #include 36 | using namespace std; 37 | #define ll long long 38 | #define N 110000 39 | ll n,m,i,j,p,q,a[N]; 40 | int main() 41 | { 42 | scanf("%lld",&n); 43 | for (i=1;i<=n;i++) 44 | scanf("%lld",&a[i]); 45 | for (i=2;i<=n;i++) 46 | { 47 | ll c=a[i]-a[i-1]; 48 | if (c>0)//不要输入 if (c) 因为c是指不为0就好了,如果c为-1,那么最后的布尔值也为1,if(c)的意思是,只要c不为0,那么条件的布尔值都为1 49 | p+=c; 50 | else 51 | q-=c; 52 | } 53 | ll ans1=max(p,q),ans2=abs(p-q)+1; 54 | cout< 15 | 第一行输入整数 N,代表士兵的数量。 16 | 17 | 接下来的 N 行,每行输入两个整数 x 和 y,分别代表一个士兵所在位置的 x 坐标和 y 坐标,第 i 行即为第 i 个士兵的坐标 (x[i],y[i])。 18 | 19 | 输出格式
20 | 输出一个整数,代表所有士兵的总移动次数的最小值。 21 | 22 | 数据范围
23 | 1≤N≤10000,
24 | −10000≤x[i],y[i]≤10000 25 | 26 | 输入样例: 27 | ``` 28 | 5 29 | 1 2 30 | 2 2 31 | 1 3 32 | 3 -2 33 | 3 3 34 | ``` 35 | 输出样例: 36 | ``` 37 | 8 38 | ``` 39 | # 参考答案 40 | ```c++ 41 | #include 42 | using namespace std; 43 | #define ll long long 44 | #define fir(a,b,c) for (ll a=b;a<=c;a++)//宏定义for循环 45 | const int N=10050; 46 | ll x[N],y[N],n,x_mid,y_mid,ans=0; 47 | int main() 48 | { 49 | ios::sync_with_stdio(false); 50 | cin>>n; 51 | fir(i,1,n) 52 | cin>>x[i]>>y[i]; 53 | sort(x+1,x+1+n); 54 | sort(y+1,y+1+n); 55 | fir(i,1,n) 56 | x[i]-=i; 57 | sort(x+1,x+1+n); 58 | x_mid=x[(n+1)>>1];//x坐标的中位数 59 | y_mid=y[(n+1)>>1];//y坐标的中位数 60 | fir(i,1,n) 61 | { 62 | ans+=abs(x[i]-x_mid); 63 | ans+=abs(y[i]-y_mid); 64 | } 65 | cout< hash; 15 | hash[nullptr] = nullptr; 16 | auto dup = new ListNode(-1), tail = dup; 17 | 18 | while(head) 19 | { 20 | if(!hash.count(head)) hash[head] = new ListNode(head->val); 21 | if(!hash.count(head->random)) hash[head->random] = new ListNode(head->random->val); 22 | 23 | tail->next = hash[head]; 24 | tail->next->random = hash[head->random]; 25 | 26 | tail = tail->next; 27 | head = head->next; 28 | } 29 | 30 | return dup->next; 31 | } 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /剑指offer/多重背包问题 I.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ![NO4.png](https://img13.360buyimg.com/ddimg/jfs/t1/176148/1/18322/33955/60e2b277E7bd5de4c/c98ccf91530f4491.png) 3 | # 参考答案 4 | ### c++代码 5 | ```c++ 6 | #include 7 | using namespace std; 8 | int a[10005],b[10005]; 9 | int main() 10 | { 11 | int t=0,n,m,dp[10005]={ },w,v,s; 12 | cin>>n>>m; 13 | while(n--) 14 | { 15 | cin>>v>>w>>s; 16 | while(s--) 17 | {a[++t]=v; 18 | b[t]=w;}//死拆,把多重背包拆成01背包 19 | } 20 | for(int i=1;i<=t;i++) 21 | for(int j=m;j>=a[i];j--) 22 | dp[j]=max(dp[j-a[i]]+b[i],dp[j]);//直接套01背包的板子 23 | cout< 7 | #include 8 | #include 9 | using namespace std; 10 | const int N = 2010; 11 | int f[N],n,m; 12 | struct good 13 | { 14 | int w,v; 15 | }; 16 | 17 | int main() 18 | { 19 | cin>>n>>m; 20 | vector Good; 21 | good tmp; 22 | 23 | //二进制处理 24 | for(int i = 1 ; i <= n ; i++ ) 25 | { 26 | int v,w,s; 27 | cin>>v>>w>>s; 28 | //坑,k <= s 29 | for(int k = 1 ; k <= s ; k*=2 ) 30 | { 31 | s-=k; 32 | Good.push_back({k*w,k*v}); 33 | } 34 | if(s>0) Good.push_back({s*w,s*v}); 35 | } 36 | 37 | //01背包优化+二进制 38 | for(auto t : Good) 39 | for(int j = m ; j >= t.v ; j--) 40 | f[j] = max(f[j] , f[j-t.v]+t.w ); //这里就是f[j] 41 | 42 | 43 | cout< 8 | #include 9 | 10 | using namespace std; 11 | 12 | const int N = 20010; 13 | 14 | int dp[N], pre[N], q[N]; 15 | int n, m; 16 | 17 | int main() { 18 | cin >> n >> m; 19 | for (int i = 0; i < n; ++i) { 20 | memcpy(pre, dp, sizeof(dp)); 21 | int v, w, s; 22 | cin >> v >> w >> s; 23 | for (int j = 0; j < v; ++j) { 24 | int head = 0, tail = -1; 25 | for (int k = j; k <= m; k += v) { 26 | 27 | if (head <= tail && k - s*v > q[head]) 28 | ++head; 29 | 30 | while (head <= tail && pre[q[tail]] - (q[tail] - j)/v * w <= pre[k] - (k - j)/v * w) 31 | --tail; 32 | 33 | if (head <= tail) 34 | dp[k] = max(dp[k], pre[q[head]] + (k - q[head])/v * w); 35 | 36 | q[++tail] = k; 37 | } 38 | } 39 | } 40 | cout << dp[m] << endl; 41 | return 0; 42 | } 43 | 44 | ``` 45 | -------------------------------------------------------------------------------- /剑指offer/奇怪的汉诺塔.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 汉诺塔问题,条件如下: 3 | 4 | 1、这里有 A、B、C 和 D 四座塔。 5 | 6 | 2、这里有 n 个圆盘,n 的数量是恒定的。 7 | 8 | 3、每个圆盘的尺寸都不相同。 9 | 10 | 4、所有的圆盘在开始时都堆叠在塔 A 上,且圆盘尺寸从塔顶到塔底逐渐增大。 11 | 12 | 5、我们需要将所有的圆盘都从塔 A 转移到塔 D 上。 13 | 14 | 6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。 15 | 16 | 请你求出将所有圆盘从塔 A 移动到塔 D,所需的最小移动次数是多少。 17 | 18 | ![image](https://user-images.githubusercontent.com/59190045/124757668-69cf9b80-df60-11eb-8e7c-d3e3031ebc92.png) 19 | 20 | 汉诺塔塔参考模型 21 | 22 | 输入格式
23 | 没有输入 24 | 25 | 输出格式
26 | 对于每一个整数 n,输出一个满足条件的最小移动次数,每个结果占一行。 27 | 28 | 数据范围
29 | 1≤n≤12 30 | 31 | 输入样例: 32 | ``` 33 | 没有输入 34 | ``` 35 | 输出样例: 36 | ``` 37 | 参考输出格式 38 | ``` 39 | # 参考答案 40 | ```c++ 41 | #include 42 | #include 43 | #include 44 | using namespace std; 45 | 46 | int d[20], f[20]; 47 | 48 | int main() { 49 | d[1] = 1; 50 | for (int i = 2; i <= 12; i++) 51 | d[i] = 2 * d[i - 1] + 1; 52 | memset(f, 0x3f, sizeof(f)); 53 | f[1] = 1; 54 | for (int i = 2; i <= 12; i++) 55 | for (int j = 1; j < i; j++) 56 | f[i] = min(f[i], 2 * f[j] + d[i - j]); 57 | for (int i = 1; i <= 12; i++) 58 | cout << f[i] << endl; 59 | return 0; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /剑指offer/字符串中第一个只出现一次的字符.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在字符串中找出第一个只出现一次的字符。 3 | 4 | 如输入"abaccdeff",则输出b。 5 | 6 | 如果字符串中不存在只出现一次的字符,返回 # 字符。 7 | 8 | 样例: 9 | ``` 10 | 输入:"abaccdeff" 11 | 12 | 输出:'b' 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | 19 | char firstNotRepeatingChar(string s) { 20 | char res = '#'; 21 | if(!s.size()) return res; 22 | unordered_map mmp; 23 | for(int i = 0; i < s.size(); i++) { 24 | mmp[s[i]] += 1; 25 | } 26 | for(int i = 0; i < s.size(); i++){ 27 | if(mmp[s[i]] == 1) 28 | return s[i]; 29 | } 30 | return res; 31 | 32 | } 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /剑指offer/字符流中第一个只出现一次的字符(1).md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 请实现一个函数用来找出字符流中第一个只出现一次的字符。 3 | 4 | 例如,当从字符流中只读出前两个字符 go 时,第一个只出现一次的字符是 g。 5 | 6 | 当从该字符流中读出前六个字符 google 时,第一个只出现一次的字符是 l。 7 | 8 | 如果当前字符流没有存在出现一次的字符,返回 # 字符。 9 | 10 | 样例 11 | ``` 12 | 输入:"google" 13 | 14 | 输出:"ggg#ll" 15 | ``` 16 | 解释:每当字符流读入一个字符,就进行一次判断并输出当前的第一个只出现一次的字符。 17 | # 参考答案 18 | ```c++ 19 | unordered_mapcount; 20 | queue q; 21 | //Insert one char from stringstream 22 | void insert(char ch){ 23 | //当新的字符已经重复,则不插入,而且将队首有可能重复的pop出来。goo,当新来第二个O, 24 | //此时队首不重复的,证明O永远不会输出,所以此时O不用插入,省一点空间。队列里只存一个O,pop的时候,count里O是两个 25 | //所以O还是可以正常pop 26 | if(++count[ch] > 1) 27 | { 28 | while(q.size() && count[q.front()] > 1) q.pop(); 29 | } 30 | else q.push(ch); 31 | } 32 | //return the first appearence once char in current stringstream 33 | char firstAppearingOnce(){ 34 | if(q.empty()) return '#'; 35 | return q.front(); 36 | } 37 | -------------------------------------------------------------------------------- /剑指offer/完全背包问题.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ![NO3.png](https://img11.360buyimg.com/ddimg/jfs/t1/177804/36/12593/33720/60e2b066Ec45f879a/4cb2792c8e4bea26.png) 3 | # 参考答案 4 | ### C++代码 5 | ```c++ 6 | #include 7 | using namespace std; 8 | const int N = 1010; 9 | int f[N]; 10 | int v[N],w[N]; 11 | int main() 12 | { 13 | int n,m; 14 | cin>>n>>m; 15 | for(int i = 1 ; i <= n ;i ++) 16 | { 17 | cin>>v[i]>>w[i]; 18 | } 19 | 20 | for(int i = 1 ; i<=n ;i++) 21 | for(int j = v[i] ; j<=m ;j++) 22 | { 23 | f[j] = max(f[j],f[j-v[i]]+w[i]); 24 | } 25 | cout< left, right; 38 | TreeNode *lc = root->left; 39 | TreeNode *rc = root->right; 40 | while(lc || rc || left.size()) 41 | { 42 | while (lc && rc) 43 | { 44 | left.push(lc), right.push(rc); 45 | lc = lc->left, rc = rc->right; 46 | } 47 | if (lc || rc) return false; 48 | lc = left.top(), rc = right.top(); 49 | left.pop(), right.pop(); 50 | if (lc->val != rc->val) return false; 51 | lc = lc->right, rc = rc->left; 52 | } 53 | return true; 54 | } 55 | 56 | }; 57 | -------------------------------------------------------------------------------- /剑指offer/左旋转字符串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 3 | 4 | 请定义一个函数实现字符串左旋转操作的功能。 5 | 6 | 比如输入字符串"abcdefg"和数字 2,该函数将返回左旋转 2 位得到的结果"cdefgab"。 7 | 8 | 注意: 9 | 10 | 数据保证 n 小于等于输入字符串的长度。 11 | 样例 12 | ``` 13 | 输入:"abcdefg" , n=2 14 | 15 | 输出:"cdefgab" 16 | ``` 17 | # 参考答案 18 | ```c++ 19 | class Solution { 20 | public: 21 | string leftRotateString(string str, int n) { 22 | 23 | return str.substr(n)+str.substr(0,n); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /剑指offer/扑克牌的顺子.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 从扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这 5 张牌是不是连续的。 3 | 4 | 2∼10 为数字本身,A 为 1,J 为 11,Q 为 12,K 为 13,大小王可以看做任意数字。 5 | 6 | 为了方便,大小王均以 0 来表示,并且假设这副牌中大小王均有两张。 7 | 8 | 样例1 9 | ``` 10 | 输入:[8,9,10,11,12] 11 | 12 | 输出:true 13 | ``` 14 | 样例2 15 | ``` 16 | 输入:[0,8,9,11,12] 17 | 18 | 输出:true 19 | ``` 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | bool isContinuous( vector numbers ) { 25 | if(numbers.size()!=5) 26 | return false; 27 | sort(numbers.begin(), numbers.end()); 28 | int zerocnt = 0; 29 | for(int i = 0;i<4;i++){ 30 | if(numbers[i]==0) 31 | zerocnt += 1; 32 | else{ 33 | if(numbers[i+1]-numbers[i]-1>zerocnt)//相邻数字间隔大于0的个数 34 | return false; 35 | if(numbers[i+1]==numbers[i])//有对子 36 | return false; 37 | zerocnt -= numbers[i+1] - numbers[i]-1; 38 | } 39 | } 40 | return true; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /剑指offer/找出数组中重复的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个长度为 n 的整数数组 nums,数组中所有的数字都在 0∼n−1 的范围内。 3 | 4 | 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。 5 | 6 | 请找出数组中任意一个重复的数字。 7 | 8 | 注意:如果某些数字不在 0∼n−1 的范围内,或数组中不包含重复数字,则返回 -1; 9 | 10 | 样例
11 | ``` 12 | 给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。 13 | 14 | 返回 2 或 3。 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | class Solution { 19 | public: 20 | int duplicateInArray(vector& nums) { 21 | int n = nums.size(); 22 | for (auto x : nums) 23 | if (x < 0 || x >= n) 24 | return -1; 25 | for (int i = 0; i < n; i ++ ) { 26 | while (nums[nums[i]] != nums[i]) swap(nums[i], nums[nums[i]]); 27 | if (nums[i] != i) return nums[i]; 28 | } 29 | return -1; 30 | } 31 | }; 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /剑指offer/把字符串转换成整数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 请你写一个函数 StrToInt,实现把字符串转换成整数这个功能。 3 | 4 | 当然,不能使用 atoi 或者其他类似的库函数。 5 | 6 | 样例 7 | ``` 8 | 输入:"123" 9 | 10 | 输出:123 11 | ``` 12 | 注意: 13 | 14 | 你的函数应满足下列条件: 15 | 16 | * 忽略所有行首空格,找到第一个非空格字符,可以是 ‘+/−’ 表示是正数或者负数,紧随其后找到最长的一串连续数字,将其解析成一个整数; 17 | * 整数后可能有任意非数字字符,请将其忽略; 18 | * 如果整数长度为 0,则返回 0; 19 | * 如果整数大于 INT_MAX(231−1),请返回 INT_MAX;如果整数小于INT_MIN(−231) ,请返回 INT_MIN; 20 | 21 | # 参考答案 22 | ```c++ 23 | class Solution { 24 | public: 25 | int strToInt(string str) { 26 | int k = 0; 27 | //去空格 28 | while(k < str.size() && str[k] == ' ') k++; 29 | bool is_minus = false; 30 | long long num = 0; 31 | //判正负 32 | if(str[k] == '+') k++; 33 | else if(str[k] == '-') k++, is_minus = true; 34 | //字符变数字 35 | while(k < str.size() && str[k] >= '0' && str[k] <= '9') { 36 | num = num * 10 + str[k] - '0'; 37 | k++; 38 | } 39 | //处理特例 40 | if(is_minus) num *= -1; 41 | if(num > INT_MAX) num = INT_MAX; 42 | if(num < INT_MIN) num = INT_MIN; 43 | return (int) num; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /剑指offer/把数字翻译成字符串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个数字,我们按照如下规则把它翻译为字符串: 3 | 4 | 0 翻译成 a,1 翻译成 b,……,11 翻译成 l,……,25 翻译成 z。 5 | 6 | 一个数字可能有多个翻译。 7 | 8 | 例如 12258 有 5 种不同的翻译,它们分别是 bccfi、bwfi、bczi、mcfi 和 mzi。 9 | 10 | 请编程实现一个函数用来计算一个数字有多少种不同的翻译方法。 11 | 12 | 样例 13 | ``` 14 | 输入:"12258" 15 | 16 | 输出:5 17 | ``` 18 | # 参考答案 19 | ```c++ 20 | /** 21 | * 1268 22 | * 1 2 6 8 23 | * 1 26 8 24 | * 12 6 8 25 | * 26 | */ 27 | class Solution { 28 | public: 29 | int getTranslationCount(string s) { 30 | int n = s.size(); 31 | if(!n) return 0; 32 | if(n==1) return 1; 33 | 34 | vector dp(n+1, 0); 35 | dp[n-1] = 1; 36 | for(int i=n-2;i>=0;i--){ 37 | dp[i] = dp[i+1]; 38 | if(s[i]=='1' || (s[i]=='2' && s[i+1]<'6')){ 39 | dp[i] += dp[i+2]; 40 | } 41 | } 42 | return dp[0]; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /剑指offer/把数组排成最小的数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。 3 | 4 | 例如输入数组 [3,32,321],则打印出这 3 个数字能排成的最小数字 321323。 5 | 6 | 样例 7 | ``` 8 | 输入:[3, 32, 321] 9 | 10 | 输出:321323 11 | ``` 12 | 注意:输出数字的格式为字符串。 13 | # 参考答案 14 | ```c++ 15 | class Solution { 16 | public: 17 | static bool myCmp(int &a, int &b) { 18 | if (to_string(a) + to_string(b) < to_string(b) + to_string(a)) 19 | return true; 20 | else return false; 21 | } 22 | string printMinNumber(vector& nums) { 23 | string str; 24 | if(!nums.size()) return str; 25 | sort(nums.begin(), nums.end(), myCmp); 26 | for(int i = 0 ; i < nums.size(); i ++ ) { 27 | str += to_string(nums[i]); 28 | } 29 | 30 | return str; 31 | } 32 | 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /剑指offer/括号画家.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 达达是一名漫画家,她有一个奇特的爱好,就是在纸上画括号。 3 | 4 | 这一天,刚刚起床的达达画了一排括号序列,其中包含小括号 ( )、中括号 [ ] 和大括号 { },总长度为 N。 5 | 6 | 这排随意绘制的括号序列显得杂乱无章,于是达达定义了什么样的括号序列是美观的: 7 | 8 | 空的括号序列是美观的;
9 | 若括号序列 A 是美观的,则括号序列 (A)、[A]、{A} 也是美观的;
10 | 若括号序列 A、B 都是美观的,则括号序列 AB 也是美观的。
11 | 例如 [(){}]() 是美观的括号序列,而)({)[}]( 则不是。
12 | 13 | 现在达达想在她绘制的括号序列中,找出其中连续的一段,满足这段子序列是美观的,并且长度尽量大。 14 | 15 | 你能帮帮她吗? 16 | 17 | 输入格式
18 | 输入一行由括号组成的字符串。 19 | 20 | 输出格式
21 | 输出一个整数,表示最长的美观的子段的长度。 22 | 23 | 数据范围
24 | 字符串长度不超过 105。 25 | 26 | 输入样例: 27 | ``` 28 | ({({(({()}})}{())})})[){{{([)()((()]]}])[{)]}{[}{) 29 | ``` 30 | 输出样例: 31 | ``` 32 | 4 33 | ``` 34 | # 参考答案 35 | ```c++ 36 | #include 37 | #include 38 | typedef long long ll; 39 | using namespace std; 40 | const int N = 1e5+7; 41 | int n,ans,f[N]; 42 | char s[N]; 43 | 44 | int main() { 45 | scanf("%s",s+1); n = strlen(s+1); 46 | f[1] = 0; 47 | for(int i = 2;i <= n; ++i) { 48 | if(s[i] == '(' || s[i] == '[' || s[i] == '{') continue; 49 | if((s[i-1-f[i-1]] == '(' && s[i] == ')') || (s[i-1-f[i-1]] == '[' && s[i] == ']') || (s[i-1-f[i-1]] == '{' && s[i] == '}')) { 50 | f[i] = f[i-1]+2+(i-2-f[i-1]? f[i-2-f[i-1]]:0); 51 | ans = max(ans,f[i]); 52 | } 53 | } 54 | cout << ans; 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /剑指offer/数值的整数次方.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 实现函数double Power(double base, int exponent),求base的 exponent次方。 3 | 4 | 不得使用库函数,同时不需要考虑大数问题。 5 | 6 | 只要输出结果与答案的绝对误差不超过 10−2 即视为正确。 7 | 8 | 注意: 9 | 10 | * 不会出现底数和指数同为0的情况 11 | * 当底数为0时,指数一定为正 12 | 13 | 样例1 14 | ``` 15 | 输入:10 ,2 16 | 输出:100 17 | ``` 18 | 样例2 19 | ``` 20 | 输入:10 ,-2 21 | 输出:0.01 22 | ``` 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | double myPow(double x, int n) { 28 | typedef long long LL; 29 | bool is_minus = n < 0; 30 | double res = 1; 31 | for (LL k = abs(LL(n)); k; k >>= 1) { 32 | if (k & 1) res *= x; 33 | x *= x; 34 | } 35 | if (is_minus) res = 1 / res; 36 | return res; 37 | } 38 | }; 39 | 40 | -------------------------------------------------------------------------------- /剑指offer/数字在排序数组中出现的次数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 统计一个数字在排序数组中出现的次数。 3 | 4 | 例如输入排序数组 [1,2,3,3,3,3,4,5] 和数字 3,由于 3 在这个数组中出现了 4 次,因此输出 4。 5 | 6 | 样例 7 | ``` 8 | 输入:[1, 2, 3, 3, 3, 3, 4, 5] , 3 9 | 10 | 输出:4 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | int getNumberOfK(vector& nums , int k) { 17 | multiset s; 18 | 19 | for(int x : nums) s.insert(x); 20 | 21 | return s.count(k); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /剑指offer/数字序列中某一位的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 数字以 0123456789101112131415… 的格式序列化到一个字符序列中。 3 | 4 | 在这个序列中,第 5 位(从 0 开始计数)是 5,第 13 位是 1,第 19 位是 4,等等。 5 | 6 | 请写一个函数求任意位对应的数字。 7 | 8 | 样例 9 | ``` 10 | 输入:13 11 | 12 | 输出:1 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | int digitAtIndex(int n) { 19 | long long i = 1, s = 9, base = 1;//i表示是几位数,s表示位数共有多少个,base表示位数的起始值。 20 | while(n > i * s) { // 9, 90, 900, 9000, 90000, i * s表示位数总共占多少位。 21 | n -= i * s; // 1000 - 9 - 90 * 2 - 900 * 3 ,当i= 3 时不符合条件,说明是在三位数里面。 22 | i ++; 23 | s *= 10; 24 | base *= 10; 25 | } 26 | int number = base + (n + i - 1) / i - 1; //求位数的第几个数, 1000 - 9 - 180 = n , n / 3 + base - 1(考虑0故减1), 向上取整 n + i - 1。 27 | int r = n % i ? n % i : i; // 除不尽就是第几位,除尽力了就是最后一位。 28 | for (int j = 0; j < i - r; j ++) number /= 10; //求数的第i - r位,取出第i - r位。 29 | 30 | return number % 10; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /剑指offer/数字排列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一组数字(可能包含重复数字),输出其所有的排列方式。 3 | 4 | 样例 5 | ``` 6 | 输入:[1,2,3] 7 | 8 | 输出: 9 | [ 10 | [1,2,3], 11 | [1,3,2], 12 | [2,1,3], 13 | [2,3,1], 14 | [3,1,2], 15 | [3,2,1] 16 | ] 17 | ``` 18 | # 参考答案 19 | ```c++ 20 | class Solution { 21 | public: 22 | vector st; 23 | vector path; 24 | vector> ans; 25 | 26 | vector> permutation(vector& nums) { 27 | sort(nums.begin(), nums.end()); 28 | st = vector(nums.size(), false); 29 | path = vector(nums.size()); 30 | dfs(nums, 0, 0); 31 | return ans; 32 | } 33 | 34 | void dfs(vector& nums, int u, int start) 35 | { 36 | if (u == nums.size()) 37 | { 38 | ans.push_back(path); 39 | return; 40 | } 41 | 42 | for (int i = start; i < nums.size(); i ++ ) 43 | if (!st[i]) 44 | { 45 | st[i] = true; 46 | path[i] = nums[u]; 47 | if (u + 1 < nums.size() && nums[u + 1] != nums[u]) 48 | dfs(nums, u + 1, 0); 49 | else 50 | dfs(nums, u + 1, i + 1); 51 | st[i] = false; 52 | } 53 | } 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /剑指offer/数据流中的中位数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 如何得到一个数据流中的中位数? 3 | 4 | 如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。 5 | 6 | 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。 7 | 8 | 样例 9 | ``` 10 | 输入:1, 2, 3, 4 11 | 12 | 输出:1,1.5,2,2.5 13 | 14 | 解释:每当数据流读入一个数据,就进行一次判断并输出当前的中位数。 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | class Solution { 19 | 20 | private PriorityQueue maxHeap=new PriorityQueue(new Comparator(){ 21 | public int compare(Integer i1,Integer i2){ 22 | return i2-i1; 23 | } 24 | });//小于中位数的集合 25 | private PriorityQueue minHeap=new PriorityQueue();//大于中位数的集合 26 | 27 | public void insert(Integer num) { 28 | if(((minHeap.size()+maxHeap.size())&1)==1){ 29 | //奇数个,就往后半部分加 30 | maxHeap.offer(num); 31 | minHeap.offer(maxHeap.poll()); 32 | }else{ 33 | //偶数个,就往前半部分加 34 | minHeap.offer(num); 35 | maxHeap.offer(minHeap.poll()); 36 | } 37 | } 38 | 39 | public Double getMedian() { 40 | if(((minHeap.size()+maxHeap.size())&1)==1){ 41 | return (double)maxHeap.peek(); 42 | }else{ 43 | return ((double)maxHeap.peek()+minHeap.peek())/2; 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /剑指offer/数组中出现次数超过一半的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 3 | 4 | 假设数组非空,并且一定存在满足条件的数字。 5 | 6 | 思考题: 7 | 8 | 假设要求只能使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢? 9 | 10 | 样例 11 | ``` 12 | 输入:[1,2,1,1,3] 13 | 14 | 输出:1 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | class Solution { 19 | public: 20 | int moreThanHalfNum_Solution(vector& nums) { 21 | int count = 1, val = nums[0]; 22 | for (int i = 1; i < nums.size(); i ++) { 23 | if (nums[i] == val) count++; 24 | else count--; 25 | if (count == 0) 26 | { 27 | val = nums[i]; 28 | count = 1; 29 | } 30 | 31 | } 32 | return val; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /剑指offer/数组中只出现一次的两个数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 一个整型数组里除了两个数字之外,其他的数字都出现了两次。 3 | 4 | 请写程序找出这两个只出现一次的数字。 5 | 6 | 你可以假设这两个数字一定存在。 7 | 8 | 样例 9 | ``` 10 | 输入:[1,2,3,3,4,4] 11 | 12 | 输出:[1,2] 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | vector findNumsAppearOnce(vector& nums) { 19 | int sum = 0; 20 | for(auto x : nums) sum ^=x; 21 | int k = 0; 22 | while(!(sum>>k & 1))k++; 23 | int first = 0; 24 | for(auto x: nums) 25 | if(x>>k&1) 26 | first ^= x; 27 | return vector{first,sum^first}; 28 | } 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /剑指offer/数组中唯一只出现一次的数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。 3 | 4 | 请找出那个只出现一次的数字。 5 | 6 | 你可以假设满足条件的数字一定存在。 7 | 8 | 思考题: 9 | 10 | 如果要求只使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢? 11 | 样例 12 | ``` 13 | 输入:[1,1,1,2,2,2,3,4,4,4] 14 | 15 | 输出:3 16 | ``` 17 | # 参考答案 18 | ```c++ 19 | class Solution { 20 | public: 21 | int findNumberAppearingOnce(vector& nums) { 22 | int ans = 0; 23 | for (int i = 31; i >= 0; --i) { 24 | int cnt = 0; 25 | for (int x: nums) { 26 | if (x >> i & 1) { 27 | cnt ++; 28 | } 29 | } 30 | if (cnt % 3 == 1) { 31 | ans = (ans * 2) + 1; 32 | } 33 | else { 34 | ans = ans * 2; 35 | } 36 | } 37 | return ans; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /剑指offer/数组中数值和下标相等的元素.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 3 | 假设一个单调递增的数组里的每个元素都是整数并且是唯一的。 4 | 5 | 请编程实现一个函数找出数组中任意一个数值等于其下标的元素。 6 | 7 | 例如,在数组 [−3,−1,1,3,5] 中,数字 3 和它的下标相等。 8 | 9 | 样例 10 | ``` 11 | 输入:[-3, -1, 1, 3, 5] 12 | 13 | 输出:3 14 | ``` 15 | 注意:如果不存在,则返回-1。 16 | # 参考答案 17 | ````c++ 18 | class Solution { 19 | public: 20 | int getNumberSameAsIndex(vector& nums) { 21 | int l=0,r=nums.size()-1; 22 | while(l>1; 25 | if(nums[mid]>=mid) r=mid; 26 | else l=mid+1; 27 | } 28 | if(nums[l]!=l) return -1; 29 | else return nums[r]; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /剑指offer/数组中的逆序对.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。 3 | 4 | 输入一个数组,求出这个数组中的逆序对的总数。 5 | 6 | 样例 7 | ``` 8 | 输入:[1,2,3,4,5,6,0] 9 | 10 | 输出:6 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | int cnt,n,c[1000000],ans; 17 | void add(int x){for(; x <= cnt; x += x & -x) c[x] ++;} 18 | int ask(int x) 19 | { 20 | int res = 0; 21 | for(; x; x -= x & -x) res += c[x]; 22 | return res; 23 | } 24 | int inversePairs(vector& nums) { 25 | set st; 26 | unordered_map ump; 27 | cnt = 0; ans = 0; n = nums.size(); 28 | memset(c, 0, sizeof c); 29 | for(auto &i : nums) st.insert(i); 30 | for(auto it = st.begin(); it != st.end(); it++ ) ump[*it] = ++cnt; 31 | for(int i = nums.size() - 1; i >= 0; i--) ans += ask(ump[nums[i]] - 1), add(ump[nums[i]]); 32 | return ans; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /剑指offer/斐波那契数列.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个整数 n ,求斐波那契数列的第 n 项。 3 | 4 | 假定从 0 开始,第 0 项为 0。(n≤39) 5 | 6 | 样例 7 | ``` 8 | 输入整数 n=5 9 | 10 | 返回 5 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | int Fibonacci(int n) { 17 | int a = 0, b = 1; 18 | while (n -- ) { 19 | int c = a + b; 20 | a = b, b = c; 21 | } 22 | return a; 23 | } 24 | }; 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /剑指offer/旋转数组的最小数字.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 3 | 4 | 输入一个升序的数组的一个旋转,输出旋转数组的最小元素。 5 | 6 | 例如数组 {3,4,5,1,2} 为 {1,2,3,4,5} 的一个旋转,该数组的最小值为 1。 7 | 8 | 数组可能包含重复项。 9 | 10 | 注意: 11 | 12 | 数组内所含元素非负,若数组大小为 0,请返回 −1。 13 | 14 | 样例 15 | ``` 16 | 输入:nums = [2, 2, 2, 0, 1] 17 | 18 | 输出:0 19 | ``` 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | int findMin(vector& nums) { 25 | int n = nums.size() - 1; 26 | if (n < 0) return -1; 27 | while (n > 0 && nums[n] == nums[0]) n -- ; 28 | if (nums[n] >= nums[0]) return nums[0]; 29 | int l = 0, r = n; 30 | while (l < r) { 31 | int mid = l + r >> 1; // [l, mid], [mid + 1, r] 32 | if (nums[mid] < nums[0]) r = mid; 33 | else l = mid + 1; 34 | } 35 | return nums[r]; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /剑指offer/替换空格.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 请实现一个函数,把字符串中的每个空格替换成"%20"。 3 | 4 | 你可以假定输入字符串的长度最大是 1000。 5 | 6 | 注意输出字符串的长度可能大于 1000。 7 | 8 | 样例 9 | ``` 10 | 输入:"We are happy." 11 | 12 | 输出:"We%20are%20happy." 13 | ``` 14 | # 参考答案 15 | ```c++ 16 | class Solution { 17 | public: 18 | string replaceSpaces(string &str) { 19 | string res; 20 | for (auto x : str) 21 | if (x == ' ') 22 | res += "%20"; 23 | else 24 | res += x; 25 | return res; 26 | } 27 | }; 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /剑指offer/最大子序和.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个长度为 n 的整数序列,从中找出一段长度不超过 m 的连续子序列,使得子序列中所有数的和最大。 3 | 4 | 注意: 子序列的长度至少是 1。 5 | 6 | 输入格式
7 | 第一行输入两个整数 n,m。 8 | 9 | 第二行输入 n 个数,代表长度为 n 的整数序列。 10 | 11 | 同一行数之间用空格隔开。 12 | 13 | 输出格式
14 | 输出一个整数,代表该序列的最大子序和。 15 | 16 | 数据范围
17 | 1≤n,m≤300000 18 | 19 | 输入样例: 20 | ``` 21 | 6 4 22 | 1 -3 5 1 -2 3 23 | ``` 24 | 输出样例: 25 | ``` 26 | 7 27 | ``` 28 | # 参考答案 29 | ```c++ 30 | #include 31 | using namespace std; 32 | #define fir(i,a,b) for(int i=a;i<=b;i++) 33 | const int N=300100; 34 | deque q; 35 | long long n,m,l,r,s[N],a[N],ans; 36 | int main() 37 | { 38 | ios::sync_with_stdio(false); 39 | cin>>n>>m; 40 | fir(i,1,n) 41 | { 42 | cin>>a[i]; 43 | s[i]=s[i-1]+a[i]; 44 | } 45 | fir(i,1,n) 46 | { 47 | while(q.size() && q.front()=s[i])//如果说队尾大于当前值的话. 51 | q.pop_back();//不需要,弹出 52 | q.push_back(i);//将i放入队尾. 53 | } 54 | cout< 7 | 数据范围
8 | 1≤k≤n≤1000
9 | 样例 10 | ``` 11 | 输入:[1,2,3,4,5,6,7,8] , k=4 12 | 13 | 输出:[1,2,3,4] 14 | ``` 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | vector getLeastNumbers_Solution(vector input, int k) { 20 | vector res; 21 | priority_queue heap; 22 | for(auto x : input) 23 | { 24 | heap.push(x); 25 | if(heap.size() > k) heap.pop(); 26 | } 27 | while(heap.size()) 28 | { 29 | res.push_back(heap.top()); 30 | heap.pop(); 31 | } 32 | reverse(res.begin(),res.end()); 33 | return res; 34 | } 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /剑指offer/最长不含重复字符的子字符串.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 3 | 4 | 假设字符串中只包含从 a 到 z 的字符。 5 | 6 | 样例 7 | ``` 8 | 输入:"abcabc" 9 | 10 | 输出:3 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | int longestSubstringWithoutDuplication(string s) { 17 | unordered_map hash; 18 | int res=0; 19 | for(int i=0,j=0;j1) 23 | { 24 | hash[s[i++]]--; 25 | } 26 | 27 | res=max(res,j-i+1); 28 | } 29 | return res; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /剑指offer/构建乘积数组.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个数组A[0, 1, …, n-1],请构建一个数组B[0, 1, …, n-1],其中B中的元素B[i]=A[0]×A[1]×… ×A[i-1]×A[i+1]×…×A[n-1]。 3 | 4 | 不能使用除法。 5 | 6 | 样例 7 | ``` 8 | 输入:[1, 2, 3, 4, 5] 9 | 10 | 输出:[120, 60, 40, 30, 24] 11 | ``` 12 | 思考题: 13 | 14 | 能不能只使用常数空间?(除了输出的数组之外) 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | vector multiply(const vector& A) { 20 | vectorleft(A.size(),1); 21 | vectorright(A.size(),1); 22 | for(int i = 1;i=0;i--){ 26 | right[i] = A[i+1]*right[i+1]; 27 | } 28 | vectorB(A.size(),0); 29 | for(int i = 0;i pushV,vector popV) { 22 | if(pushV.empty() || popV.empty() || pushV.size()!=popV.size()) return false; 23 | stack s; 24 | int popId=0; 25 | 26 | 27 | for(int pushId=0;pushId 9 | 输入的两个节点一定不为空,且是二叉树中的节点; 10 | 样例 11 | ``` 12 | 二叉树[8, 12, 2, null, null, 6, 4, null, null, null, null]如下图所示: 13 | 8 14 | / \ 15 | 12 2 16 | / \ 17 | 6 4 18 | 19 | 1. 如果输入的树节点为2和12,则输出的最低公共祖先为树节点8。 20 | 21 | 2. 如果输入的树节点为2和6,则输出的最低公共祖先为树节点2。 22 | ``` 23 | # 参考答案 24 | ```c++ 25 | class Solution { 26 | public: 27 | TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 28 | if(!root) 29 | return NULL; 30 | if(root==p||root==q) 31 | return root; 32 | TreeNode* left = lowestCommonAncestor(root->left, p, q); 33 | TreeNode* right = lowestCommonAncestor(root->right, p, q); 34 | if(left&&right) 35 | return root; 36 | if(left==NULL) 37 | return right; 38 | else 39 | return left; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /剑指offer/树的子结构.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入两棵二叉树 A,B,判断 B 是不是 A 的子结构。 3 | 4 | 我们规定空树不是任何树的子结构。 5 | 6 | 样例 7 | ``` 8 | 树 A: 9 | 10 | 8 11 | / \ 12 | 8 7 13 | / \ 14 | 9 2 15 | / \ 16 | 4 7 17 | 树 B: 18 | 19 | 8 20 | / \ 21 | 9 2 22 | ``` 23 | 返回 true,因为 B 是 A 的子结构。 24 | 25 | # 参考答案 26 | ```c++ 27 | /** 28 | * Definition for a binary tree node. 29 | * struct TreeNode { 30 | * int val; 31 | * TreeNode *left; 32 | * TreeNode *right; 33 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 34 | * }; 35 | */ 36 | class Solution { 37 | public: 38 | bool hasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { 39 | if (!pRoot1 || !pRoot2) return false; 40 | if (isSame(pRoot1, pRoot2)) return true; 41 | return hasSubtree(pRoot1->left, pRoot2) || hasSubtree(pRoot1->right, pRoot2); 42 | } 43 | 44 | bool isSame(TreeNode* pRoot1, TreeNode* pRoot2) { 45 | if (!pRoot2) return true; 46 | if (!pRoot1 || pRoot1->val != pRoot2->val) return false; 47 | return isSame(pRoot1->left, pRoot2->left) && isSame(pRoot1->right, pRoot2->right); 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /剑指offer/正则表达式匹配.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 请实现一个函数用来匹配包括'.'和'*'的正则表达式。 3 | 4 | 模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。 5 | 6 | 在本题中,匹配是指字符串的所有字符匹配整个模式。 7 | 8 | 例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。 9 | 10 | 样例 11 | ``` 12 | 输入: 13 | 14 | s="aa" 15 | p="a*" 16 | 17 | 输出:true 18 | ``` 19 | 20 | # 参考答案 21 | ```c++ 22 | class Solution { 23 | public: 24 | vector>f; 25 | int n, m; 26 | bool isMatch(string s, string p) { 27 | n = s.size(); 28 | m = p.size(); 29 | f = vector>(n + 1, vector(m + 1, -1)); 30 | return dp(0, 0, s, p); 31 | } 32 | 33 | bool dp(int x, int y, string &s, string &p) 34 | { 35 | if (f[x][y] != -1) return f[x][y]; 36 | if (y == m) 37 | return f[x][y] = x == n; 38 | bool first_match = x < n && (s[x] == p[y] || p[y] == '.'); 39 | bool ans; 40 | if (y + 1 < m && p[y + 1] == '*') 41 | { 42 | ans = dp(x, y + 2, s, p) || first_match && dp(x + 1, y, s, p); 43 | } 44 | else 45 | ans = first_match && dp(x + 1, y + 1, s, p); 46 | return f[x][y] = ans; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /剑指offer/求1+2+…+n.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 求 1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case 等关键字及条件判断语句 (A?B:C)。 3 | 4 | 样例 5 | ``` 6 | 输入:10 7 | 8 | 输出:55 9 | ``` 10 | # 参考答案 11 | ```c++ 12 | class Solution { 13 | public: 14 | int getSum(int n) { 15 | char a[n][n+1]; 16 | return sizeof(a)>>1; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /剑指offer/混合背包问题.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ![7-混合背包问题.png](https://img10.360buyimg.com/ddimg/jfs/t1/193093/27/11638/65289/60e2b5a0E0a85034f/cd3e7a080652d03a.png) 3 | # 参考答案 4 | ### c++代码 5 | ```c++ 6 | #include 7 | using namespace std; 8 | int n,m,v[100010],w[100010],f[100010]; 9 | int main() 10 | { 11 | cin>>n>>m; 12 | int cnt=1; 13 | for(int i=1;i<=n;i++) 14 | { 15 | int a,b,s; 16 | cin>>a>>b>>s; 17 | int k=1; 18 | if(s<0)s=1; 19 | else if(s==0)s=m/a;//把01背包和多重背包先转化成多重背包,若为完全背包,则在最优情况下,只能取总体积/该物品体积向下取整 20 | while(k<=s) 21 | { 22 | v[cnt]=a*k; 23 | w[cnt]=b*k; 24 | s-=k; 25 | k*=2; 26 | cnt++; 27 | } 28 | if(s>0) 29 | { 30 | v[cnt]=s*a; 31 | w[cnt]=s*b; 32 | cnt++; 33 | } 34 | }//将多重背包进行二进制优化,变成01背包 35 | for(int i=1;i<=cnt;i++) 36 | { 37 | for(int j=m;j>=v[i];j--) 38 | { 39 | f[j]=max(f[j],f[j-v[i]]+w[i]); 40 | } 41 | }//01背包问题 42 | cout< maxInWindows(vector& nums, int k) { 20 | vectorres; 21 | dequeq; 22 | for(int i = 0; i < nums.size(); i++){ 23 | if(!q.empty() && i-q.front() >= k)//判断队头是否需要出队 24 | q.pop_front(); 25 | while(!q.empty()&&nums[q.back()]= k-1){ 29 | res.push_back(nums[q.front()]);//取队头作为窗口最大元素 30 | } 31 | } 32 | return res; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /剑指offer/特殊排序.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 有 N 个元素,编号 1,2..N,每一对元素之间的大小关系是确定的,关系具有反对称性,但不具有传递性。 3 | 4 | 注意:不存在两个元素大小相等的情况。 5 | 6 | 也就是说,元素的大小关系是 N 个点与 (N×(N−1))/2 条有向边构成的任意有向图。 7 | 8 | 然而,这是一道交互式试题,这些关系不能一次性得知,你必须通过不超过 10000 次提问来获取信息,每次提问只能了解某两个元素之间的关系。 9 | 10 | 现在请你把这 N 个元素排成一行,使得每个元素都小于右边与它相邻的元素。 11 | 12 | 你可以通过我们预设的 bool 函数 compare 来获得两个元素之间的大小关系。 13 | 14 | 例如,编号为 a 和 b 的两个元素,如果元素 a 小于元素 b,则 compare(a,b) 返回 true,否则返回 false。 15 | 16 | 将 N 个元素排好序后,把他们的编号以数组的形式输出,如果答案不唯一,则输出任意一个均可。 17 | 18 | 数据范围
19 | 1≤N≤1000 20 | 21 | 输入样例 22 | ``` 23 | [[0, 1, 0], [0, 0, 0], [1, 1, 0]] 24 | ``` 25 | 输出样例 26 | ``` 27 | [3, 1, 2] 28 | ``` 29 | # 参考答案 30 | ```c++ 31 | class Solution { 32 | public: 33 | vector specialSort(int N) { 34 | vector res; 35 | res.push_back(1); 36 | for(int i = 2;i <= N;i++){ 37 | int l = 0,r = res.size() - 1; 38 | while(l <= r){ 39 | int mid = l + r >> 1; 40 | if(compare(res[mid],i)) l = mid + 1; 41 | else r = mid - 1; 42 | } 43 | res.push_back(i); 44 | for(int j = res.size() - 2;j > r;j--) swap(res[j],res[j + 1]); 45 | } 46 | return res; 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /剑指offer/礼物的最大价值.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在一个 m×n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。 3 | 4 | 你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格直到到达棋盘的右下角。 5 | 6 | 给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物? 7 | 8 | 注意: 9 | 10 | m,n>0 11 | 样例: 12 | ``` 13 | 输入: 14 | [ 15 | [2,3,1], 16 | [1,7,1], 17 | [4,6,1] 18 | ] 19 | 20 | 输出:19 21 | 22 | 解释:沿着路径 2→3→7→6→1 可以得到拿到最大价值礼物。 23 | ``` 24 | # 参考答案 25 | ```c++ 26 | class Solution { 27 | public: 28 | int getMaxValue(vector>& grid) { 29 | for(int i=0;i 11 | 第一行输入一个正整数 n,表示小朋友的个数。 12 | 13 | 接下来 n 行,每行一个整数 a[i],表示第 i 个小朋友初始得到的糖果的颗数。 14 | 15 | 输出格式
16 | 输出一个整数,表示最小代价。 17 | 18 | 数据范围
19 | 1≤n≤1000000,
20 | 0≤a[i]≤2×109,
21 | 数据保证一定有解。 22 | 23 | 输入样例: 24 | ``` 25 | 4 26 | 1 27 | 2 28 | 5 29 | 4 30 | ``` 31 | 输出样例: 32 | ``` 33 | 4 34 | ``` 35 | # 参考答案 36 | ```c++ 37 | #include 38 | #include 39 | #define ll long long 40 | using namespace std; 41 | int n,a[1000001],c[1000001],ave;ll sum; 42 | int main() 43 | { 44 | scanf("%d",&n); 45 | for(int i=1;i<=n;i++) 46 | { 47 | scanf("%d",&a[i]); 48 | sum+=a[i]; 49 | } 50 | ave=sum/n; 51 | 52 | for(int i=2;i<=n;i++) 53 | c[i]=c[i-1]+a[i]-ave; 54 | sort(c+1,c+n+1); 55 | 56 | 57 | 58 | ll ans=0; 59 | int mid=c[(n>>1)+1]; 60 | for(int i=1;i<=n;i++) 61 | ans+=abs(c[i]-mid); 62 | printf("%lld",ans); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /剑指offer/翻转单词顺序.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个英文句子,单词之间用一个空格隔开,且句首和句尾没有多余空格。 3 | 4 | 翻转句子中单词的顺序,但单词内字符的顺序不变。 5 | 6 | 为简单起见,标点符号和普通字母一样处理。 7 | 8 | 例如输入字符串"I am a student.",则输出"student. a am I"。 9 | 10 | 样例 11 | ``` 12 | 输入:"I am a student." 13 | 14 | 输出:"student. a am I" 15 | ``` 16 | # 参考答案 17 | ```c++ 18 | class Solution { 19 | public: 20 | string reverseWords(string s) 21 | { 22 | if(!s.size()) return "" ; //特判 23 | vector words ; //1 存储单词 24 | for(int i=0,j=0;i& nums) { 19 | if(nums.size()==0) return 0; 20 | int buy=nums[0],diff=0; 21 | for(auto &x:nums){ 22 | if(xdiff) diff=x-buy; 24 | } 25 | return diff; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /剑指offer/背包问题.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | ![NO2.png](https://img13.360buyimg.com/ddimg/jfs/t1/184488/3/12594/34414/60e2aea7Ea8efe992/d9741f321f559b9e.png) 3 | # 参考答案 4 | ### C++代码 5 | ```c++ 6 | #include 7 | 8 | using namespace std; 9 | 10 | const int MAXN = 1005; 11 | int v[MAXN]; // 体积 12 | int w[MAXN]; // 价值 13 | int f[MAXN][MAXN]; // f[i][j], j体积下前i个物品的最大价值 14 | 15 | int main() 16 | { 17 | int n, m; 18 | cin >> n >> m; 19 | for(int i = 1; i <= n; i++) 20 | cin >> v[i] >> w[i]; 21 | 22 | for(int i = 1; i <= n; i++) 23 | for(int j = 1; j <= m; j++) 24 | { 25 | // 当前背包容量装不进第i个物品,则价值等于前i-1个物品 26 | if(j < v[i]) 27 | f[i][j] = f[i - 1][j]; 28 | // 能装,需进行决策是否选择第i个物品 29 | else 30 | f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]); 31 | } 32 | 33 | cout << f[n][m] << endl; 34 | 35 | return 0; 36 | } 37 | ``` 38 | 39 | 40 | -------------------------------------------------------------------------------- /剑指offer/调整数组顺序使奇数位于偶数前面.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序。 3 | 4 | 使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分。 5 | 6 | 样例 7 | ``` 8 | 输入:[1,2,3,4,5] 9 | 10 | 输出: [1,3,5,2,4] 11 | ``` 12 | # 参考答案 13 | ```c++ 14 | class Solution { 15 | public: 16 | void reOrderArray(vector &array) { 17 | int l = 0, r = array.size() - 1; 18 | while (l < r) { 19 | while (l < r && array[l] % 2 == 1) l ++ ; 20 | while (l < r && array[r] % 2 == 0) r -- ; 21 | if (l < r) swap(array[l], array[r]); 22 | } 23 | } 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /剑指offer/货仓选址.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 在一条数轴上有 N 家商店,它们的坐标分别为 A1∼AN。 3 | 4 | 现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。 5 | 6 | 为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。 7 | 8 | 输入格式
9 | 第一行输入整数 N。 10 | 11 | 第二行 N 个整数 A1∼AN。 12 | 13 | 输出格式
14 | 输出一个整数,表示距离之和的最小值。 15 | 16 | 数据范围
17 | 1≤N≤100000,
18 | 0≤Ai≤40000 19 | 20 | 输入样例: 21 | ``` 22 | 4 23 | 6 2 9 1 24 | ``` 25 | 输出样例: 26 | ``` 27 | 12 28 | ``` 29 | # 参考答案 30 | ```c++ 31 | #include 32 | using namespace std; 33 | const int N=100100; 34 | int a[N],n,i,ans,sum; 35 | int main() 36 | { 37 | cin>>n; 38 | for (i=1;i<=n;i++) 39 | cin>>a[i]; 40 | sort(a+1,a+1+n);//排序 41 | int sm=a[n/2+1];//中位数 42 | for (i=1;i<=n;i++) 43 | ans=ans+abs(a[i]-sm);//统计和中位数之间的差 44 | cout<& nums) { 21 | int s = 0; 22 | int res = INT_MIN; // **1 23 | for(auto x : nums) 24 | { 25 | if(s < 0) s = 0; 26 | s += x; 27 | 28 | res = max(res, s); // **2 29 | } 30 | 31 | return res; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /剑指offer/递归实现指数型枚举 .md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。 3 | 4 | 输入格式
5 | 输入一个整数 n。 6 | 7 | 输出格式
8 | 每行输出一种方案。 9 | 10 | 同一行内的数必须升序排列,相邻两个数用恰好 1 个空格隔开。 11 | 12 | 对于没有选任何数的方案,输出空行。 13 | 14 | 本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。 15 | 16 | 数据范围
17 | 1≤n≤15
18 | 19 | 输入样例: 20 | ``` 21 | 3 22 | ``` 23 | 输出样例: 24 | ``` 25 | 3 26 | 2 27 | 2 3 28 | 1 29 | 1 3 30 | 1 2 31 | 1 2 3 32 | ``` 33 | # 参考答案 34 | ```c++ 35 | #include 36 | using namespace std; 37 | 38 | int n; 39 | 40 | // u是当前枚举到的数,state是二进制数记录哪些数被选 41 | void dfs(int u, int state) { 42 | if (u == n) { 43 | for (int i = 0; i < n; i ++) 44 | if (state >> i & 1) 45 | cout << i + 1 << " "; 46 | cout << endl; 47 | return ; 48 | } 49 | 50 | dfs (u + 1, state); // 不用u这个数 51 | dfs (u + 1, state | (1 << u)); // 用u这个数 52 | } 53 | 54 | int main() { 55 | cin >> n; 56 | dfs(0, 0); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /剑指offer/递归实现排列型枚举.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 把 1∼n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。 3 | 4 | 输入格式
5 | 一个整数 n。 6 | 7 | 输出格式
8 | 按照从小到大的顺序输出所有方案,每行 1 个。 9 | 10 | 首先,同一行相邻两个数用一个空格隔开。 11 | 12 | 其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。 13 | 14 | 数据范围
15 | 1≤n≤9 16 | 17 | 输入样例: 18 | ``` 19 | 3 20 | ``` 21 | 输出样例: 22 | ``` 23 | 1 2 3 24 | 1 3 2 25 | 2 1 3 26 | 2 3 1 27 | 3 1 2 28 | 3 2 1 29 | ``` 30 | # 参考答案 31 | ```c++ 32 | #include 33 | using namespace std; 34 | const int N = 10; 35 | int path[N];//保存序列 36 | int state[N];//数字是否被用过 37 | int n; 38 | void dfs(int u) 39 | { 40 | if(u > n)//数字填完了,输出 41 | { 42 | for(int i = 1; i <= n; i++)//输出方案 43 | cout << path[i] << " "; 44 | cout << endl; 45 | } 46 | 47 | for(int i = 1; i <= n; i++)//空位上可以选择的数字为:1 ~ n 48 | { 49 | if(!state[i])//如果数字 i 没有被用过 50 | { 51 | path[u] = i;//放入空位 52 | state[i] = 1;//数字被用,修改状态 53 | dfs(u + 1);//填下一个位 54 | state[i] = 0;//回溯,取出 i 55 | } 56 | } 57 | } 58 | 59 | int main() 60 | { 61 | 62 | cin >> n; 63 | dfs(1); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /剑指offer/递归实现组合型枚举.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。 3 | 4 | 输入格式
5 | 两个整数 n,m ,在同一行用空格隔开。 6 | 7 | 输出格式
8 | 按照从小到大的顺序输出所有方案,每行 1 个。 9 | 10 | 首先,同一行内的数升序排列,相邻两个数用一个空格隔开。 11 | 12 | 其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。 13 | 14 | 数据范围
15 | n>0 ,
16 | 0≤m≤n ,
17 | n+(n−m)≤25 18 | 19 | 输入样例: 20 | ``` 21 | 5 3 22 | ``` 23 | 输出样例: 24 | ``` 25 | 1 2 3 26 | 1 2 4 27 | 1 2 5 28 | 1 3 4 29 | 1 3 5 30 | 1 4 5 31 | 2 3 4 32 | 2 3 5 33 | 2 4 5 34 | 3 4 5 35 | ``` 36 | 思考题:如果要求使用非递归方法,该怎么做呢? 37 | # 参考答案 38 | ```c++ 39 | #include 40 | using namespace std; 41 | 42 | int n,m; 43 | vector num; 44 | 45 | void dfs(int k) 46 | { 47 | //如题解所述 48 | if(num.size() > m || num.size() + (n - k + 1) < m) 49 | return; 50 | //到达枚举边界,输出结果并结束 51 | if(k == n + 1) 52 | { 53 | for(int i = 0;i < num.size();++i) 54 | cout << num[i] << " "; 55 | 56 | cout << endl; 57 | return; 58 | } 59 | 60 | //选择这个数 61 | num.push_back(k); 62 | dfs(k+1); 63 | //回溯 64 | num.pop_back(); 65 | 66 | //不选择这个数 67 | dfs(k+1); 68 | } 69 | 70 | int main(void) 71 | { 72 | cin >> n >> m; 73 | 74 | dfs(1); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /剑指offer/重建二叉树.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。 3 | 4 | 注意: 5 | 6 | 二叉树中每个节点的值都互不相同;
7 | 输入的前序遍历和中序遍历一定合法; 8 | 9 | 样例 10 | ``` 11 | 给定: 12 | 前序遍历是:[3, 9, 20, 15, 7] 13 | 中序遍历是:[9, 3, 15, 20, 7] 14 | 15 | 返回:[3, 9, 20, null, null, 15, 7, null, null, null, null] 16 | 返回的二叉树如下所示: 17 | 3 18 | / \ 19 | 9 20 20 | / \ 21 | 15 7 22 | ``` 23 | # 参考答案 24 | ```c++ 25 | /** 26 | * Definition for a binary tree node. 27 | * struct TreeNode { 28 | * int val; 29 | * TreeNode *left; 30 | * TreeNode *right; 31 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 32 | * }; 33 | */ 34 | class Solution { 35 | public: 36 | 37 | unordered_map pos; 38 | 39 | TreeNode* buildTree(vector& preorder, vector& inorder) { 40 | int n = preorder.size(); 41 | for (int i = 0; i < n; i ++ ) 42 | pos[inorder[i]] = i; 43 | return dfs(preorder, inorder, 0, n - 1, 0, n - 1); 44 | } 45 | 46 | TreeNode* dfs(vector&pre, vector&in, int pl, int pr, int il, int ir) 47 | { 48 | if (pl > pr) return NULL; 49 | int k = pos[pre[pl]] - il; 50 | TreeNode* root = new TreeNode(pre[pl]); 51 | root->left = dfs(pre, in, pl + 1, pl + k, il, il + k - 1); 52 | root->right = dfs(pre, in, pl + k + 1, pr, il + k + 1, ir); 53 | return root; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /剑指offer/链表中倒数第k个节点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个链表,输出该链表中倒数第 k 个结点。 3 | 4 | 注意: 5 | 6 | k >= 1;
7 | 如果 k 大于链表长度,则返回 NULL; 8 | 9 | 样例 10 | ``` 11 | 输入:链表:1->2->3->4->5 ,k=2 12 | 13 | 输出:4 14 | ``` 15 | # 参考答案 16 | ```c++ 17 | /** 18 | * Definition for singly-linked list. 19 | * struct ListNode { 20 | * int val; 21 | * ListNode *next; 22 | * ListNode(int x) : val(x), next(NULL) {} 23 | * }; 24 | */ 25 | class Solution { 26 | public: 27 | ListNode* findKthToTail(ListNode* head, int k) { 28 | int n = 0; 29 | for (auto p = head; p; p = p->next) n ++ ; 30 | if (n < k) return nullptr; 31 | auto p = head; 32 | for (int i = 0; i < n - k; i ++ ) p = p->next; 33 | return p; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /剑指offer/链表中环的入口结点.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 给定一个链表,若其中包含环,则输出环的入口节点。 3 | 4 | 若其中不包含环,则输出null。 5 | 6 | 样例 7 | 8 | ![image](https://user-images.githubusercontent.com/59190045/124710107-e3e72c80-df2e-11eb-9174-5fb2cd2f2b4e.png) 9 | 10 | ``` 11 | 给定如上所示的链表: 12 | [1, 2, 3, 4, 5, 6] 13 | 2 14 | 注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。 15 | 16 | 则输出环的入口节点3. 17 | ``` 18 | # 参考答案 19 | ```c++ 20 | /** 21 | * Definition for singly-linked list. 22 | * struct ListNode { 23 | * int val; 24 | * ListNode *next; 25 | * ListNode(int x) : val(x), next(NULL) {} 26 | * }; 27 | */ 28 | class Solution { 29 | public: 30 | ListNode *entryNodeOfLoop(ListNode *head) { 31 | if (!head || !head->next) return 0; 32 | ListNode *first = head, *second = head; 33 | 34 | while (first && second) 35 | { 36 | first = first->next; 37 | second = second->next; 38 | if (second) second = second->next; 39 | else return 0; 40 | 41 | if (first == second) 42 | { 43 | first = head; 44 | while (first != second) 45 | { 46 | first = first->next; 47 | second = second->next; 48 | } 49 | return first; 50 | } 51 | } 52 | 53 | return 0; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /剑指offer/顺时针打印矩阵.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 3 | 4 | 样例 5 | ``` 6 | 输入: 7 | [ 8 | [1, 2, 3, 4], 9 | [5, 6, 7, 8], 10 | [9,10,11,12] 11 | ] 12 | 13 | 输出:[1,2,3,4,8,12,11,10,9,5,6,7] 14 | ``` 15 | # 参考答案 16 | ```c++ 17 | class Solution { 18 | public: 19 | vector printMatrix(vector>& matrix) { 20 | vector res; 21 | if (matrix.empty()) return res; 22 | int n = matrix.size(), m = matrix[0].size(); 23 | vector> st(n, vector(m, false)); 24 | int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; 25 | int x = 0, y = 0, d = 1; 26 | for (int k = 0; k < n * m; k ++ ) 27 | { 28 | res.push_back(matrix[x][y]); 29 | st[x][y] = true; 30 | 31 | int a = x + dx[d], b = y + dy[d]; 32 | if (a < 0 || a >= n || b < 0 || b >= m || st[a][b]) 33 | { 34 | d = (d + 1) % 4; 35 | a = x + dx[d], b = y + dy[d]; 36 | } 37 | x = a, y = b; 38 | } 39 | return res; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /剑指offer/骰子的点数.md: -------------------------------------------------------------------------------- 1 | # 题目 2 | 将一个骰子投掷 n 次,获得的总点数为 s,s 的可能范围为 n∼6n。 3 | 4 | 掷出某一点数,可能有多种掷法,例如投掷 2 次,掷出 3 点,共有 [1,2],[2,1] 两种掷法。 5 | 6 | 请求出投掷 n 次,掷出 n∼6n 点分别有多少种掷法。 7 | 8 | 样例1 9 | ``` 10 | 输入:n=1 11 | 12 | 输出:[1, 1, 1, 1, 1, 1] 13 | 14 | 解释:投掷1次,可能出现的点数为1-6,共计6种。每种点数都只有1种掷法。所以输出[1, 1, 1, 1, 1, 1]。 15 | ``` 16 | 样例2 17 | ``` 18 | 输入:n=2 19 | 20 | 输出:[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1] 21 | 22 | 解释:投掷2次,可能出现的点数为2-12,共计11种。每种点数可能掷法数目分别为1,2,3,4,5,6,5,4,3,2,1。 23 | 24 | 所以输出[1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]。 25 | ``` 26 | # 参考答案 27 | ```c++ 28 | class Solution { 29 | public: 30 | vector numberOfDice(int n) { 31 | vectordp(6*n+1, 0); 32 | for(int i = 1;i<=6;i++)//动归数组初始值,表示1个骰子扔出1-6的可能数都为1 33 | dp[i] = 1; 34 | for(int i = 2;i<=n;i++){ 35 | for(int j = 6*i;j>=0;j--){ 36 | dp[j] = 0; 37 | for(int k = 6;k>=1;k--){//最后一个骰子可以扔1-6点 38 | if(j-k<0) 39 | continue; 40 | dp[j] += dp[j-k]; 41 | } 42 | } 43 | } 44 | vectorres(dp.begin()+n, dp.end());//扔n个骰子的和为[n, 6*n] 45 | return res; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /图/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /堆与栈/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /字符串/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /并发/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /排序/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /操作系统/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /树/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /编译原理/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /编译原理/1~9 编译原理面试题.md: -------------------------------------------------------------------------------- 1 | # 1、什么是语法分析? 2 | 识别由词法分析给出的单词符号串是否是给定文法的正确句子(程序) 3 | # 2、什么是自顶向下分析法? 4 | * 面向目标的分析方法 5 | * 也就是从文法的开始符号企图推导出与输入的单词符号串完全相匹配的句子,若是输入串是给定文法的句子,则必能推导出,反之则必然出错。 6 | # 3、在自顶向下的分析过程中,存在的问题是什么? 7 | 需对文法有一定限制 8 | # 4、什么是确定的自顶向下分析法? 9 | * 定义: 确定的自顶向下分析方法,是从文法的开始符号出发,考虑如何根据当前的输入符号 (单词符号)唯一地确定选用哪个产生式替换相应非终结符以往下推导,或如何构造一棵相 应的语法树。 10 | * 特点:实现方法简单、直观,便于手工构造或自动生成语法分析器,是最常用的语法分析方法之一 11 | * 区别:自顶向下的不确定分析方法是带回溯的分析方法 12 | # 5、存在的问题 13 | 当一个非终结符号对应若干个规则时,选择哪个规则的右部对该非终结符号进行展开呢?
14 | 例如:如果要被代换的最左非终结符号是U,且有n条规则:U::=A1|A2|…|An,那么如何确定用哪个规则的右部去替代U? 15 | # 6、gcc hello.c 这行命令具体的执行过程,内部究竟做了什么? 16 | # 7、程序一定会从main函数开始运行吗? 17 | # 8、如何确定某个函数有被编译输出? 18 | # 9、动态链接库和静态链接库的区别是什么? 19 | -------------------------------------------------------------------------------- /网络原理/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /网络编程/1.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /语言语法/1.txt: -------------------------------------------------------------------------------- 1 | 1 --------------------------------------------------------------------------------