├── .gitignore ├── .idea ├── branin-model-tool.iml ├── codeStyles │ └── codeStyleConfig.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── DFS.md ├── DFS ├── 1020-medium-飞地的数量.js ├── 120-medium-三角形最小路径和.js ├── 1239-medium-串联字符串的最大长度.js ├── 1376.-medium-通知所有员工所需的时间.js ├── 17-medium-电话号码的字母组合.js ├── 200-medium-岛屿数量.js ├── 216-medium-组合总和3.js ├── 22-medium-括号生成.js ├── 312-hard-戳气球.js ├── 377-medium-组合总和4.js ├── 39-medium-组合总和.js ├── 40-medium-组合总和2.js ├── 46-medium-全排列.js ├── 47-medium-全排列2.js ├── 494-medium-目标和.js ├── 5418-medium-二叉树中的伪回文路径.js ├── 60-medium-第K个排列.js ├── 695-medium-岛屿的最大面积.js ├── 77-medium-组合.js ├── 784-easy-字母大小写全排列.js ├── 797-medium-所有可能的路径.js ├── 841-medium-钥匙和房间.js └── 90-medium-子集2.js ├── img └── fe-algo.jpeg ├── readme-copy.md ├── readme.md ├── test.js ├── test2.js ├── 二分查找.md ├── 二分查找 ├── 162-medium-寻找峰值.js ├── 240-medium-搜索二维矩阵2.js ├── 275-medium-h指数2.js ├── 33-medium-搜索旋转排序数组.js ├── 374-easy-猜数字大小.js ├── 441-easy-排列硬币.js ├── 704-easy-二分查找.js ├── 744-easy-寻找比目标字母大的最小字母.js └── 81-medium-搜索旋转排序数组2.js ├── 位运算.md ├── 位运算 ├── 1318-medium-或运算的最小翻转次数.js ├── 137-medium-只出现一次的元素2.js ├── 1486-easy-数组异或操作.js ├── 190-easy-颠倒二进制位.js ├── 191-easy-位1的个数.js ├── 210-medium-数字范围按位与.js ├── 260-medium-只出现一次的数字3.js ├── 338-medium-比特位计数.js ├── 342-easy-4的幂.js ├── 397-medium-整数替换.js ├── 461-easy-汉明距离.js ├── 476-easy-数字的补数.js ├── 477-medium-汉明距离总和.js ├── 5409-medium-检查一个字符串是否包含所有长度为 K 的二进制子串.js ├── 693-easy-交替位二进制数.js ├── 762-easy-二进制表示中质数个计算置位.js └── 784-easy-字母大小写全排列.js ├── 其他 └── 705-easy-设计哈希集合.js ├── 剑指offer ├── 03-easy-数组中重复的数字.js ├── 05-easy-替换空格.js ├── 06-easy-从尾到头打印链表.js ├── 10-easy-斐波那契数列.js ├── 15-easy-二进制中1的个数.js ├── 17-easy-打印从1到最大的n位数.js ├── 18-easy-删除链表的节点.js ├── 22-easy-链表中倒数第k个节点.js ├── 27-easy-二叉树的镜像.js ├── 32-easy-从上到下打印二叉树 II.js ├── 32-medium-从上到下打印二叉树.js ├── 38-medium-字符串的排列.js ├── 53-easy-II. 0~n-1中缺失的数字.js ├── 53-easy-在排序数组中查找数字.js ├── 54-easy- 二叉搜索树的第k大节点.js ├── 55-easy-二叉树的深度.js ├── 56-1-medium-数组中数字出现的次数.js ├── 56-medium-数组中数字出现的次数2.js ├── 57-easy-和为s的两个数字.js ├── 58-easy-左旋转字符串.js ├── 58-easy-翻转单词顺序1.js ├── 59 - I-easy-滑动窗口的最大值.js ├── 61-easy-扑克牌中的顺子.js ├── 62-easy-圆圈中最后剩下的数字.js ├── 63-medium-股票的最大利润.js └── 66-easy-构建乘积数组.js ├── 动态规划.md ├── 动态规划 ├── 1143-medium-最长公共子序列.js ├── 1277-medium-统计全为 1 的正方形子矩阵.js ├── 152-medium-乘积最大子序列.js ├── 198-easy-打家劫舍.js ├── 213-medium-打家劫舍2.js ├── 221-medium-最大正方形.js ├── 279-medium-完全平方数.js ├── 300-medium-最长上升子序列.js ├── 322-medium-零钱兑换.js ├── 375-medium-猜数字大小2.js ├── 416-medium-分割等和子集.js ├── 53-easy-最大子序和.js ├── 5363-hard-做菜顺序.js ├── 5383-hard-给 N x 3 网格图涂色的方案数.js ├── 583-medium-两个字符串的删除操作.js ├── 62-medium-不同路径.js ├── 63-medium-不同路径2.js ├── 64-medium-最小路径和.js ├── 70-easy-爬楼梯.js ├── 746-easy-使用最小花费爬楼梯.js └── 931-medium-下降路径最小和.js ├── 博弈 └── 取球游戏.js ├── 双指针.md ├── 双指针 ├── 11-medium-盛最多水的容器.js ├── 287-lookforRepeatNumber.js ├── 345-revertChar.js ├── 349-twoArrIntersection.js ├── 350-easy-两个数组交集2.js ├── 5417-medium-定长子串中元音的最大数目.js ├── 674-easy-最长连续递增序列.js ├── 881-medium-救生艇.js ├── 925-长按键入.js ├── 986-medium-区间列表的交集.js └── 滑动窗口 │ └── 1004-medium-最大连续1的个数3.js ├── 周六 ├── 1009-easy-十进制整数的反码.js ├── 1103-easy-分糖果2.js ├── 215-medium-数组中的第K个最大元素.js ├── 238-medium-除自身外数组的乘积.js ├── 386-medium-字典序排数.js ├── 48-medium-旋转图像.js ├── 77-medium-组合.js ├── 791-medium-自定义字符串排序.js ├── 868-easy-二进制间距.js ├── 876-链表的中间节点.js ├── 908-easy-最小差值1.js └── 965-easy-单值二叉树.js ├── 周赛 ├── 1.js ├── 2.js ├── 3.js └── 4.js ├── 周赛2 ├── 1.js ├── 2.js ├── 3.js ├── 4.js └── 5.js ├── 周赛3 ├── 1.js ├── 2.js ├── 3.js ├── 4.js └── 5.js ├── 周赛4 ├── 2.js ├── 3.js ├── 4.js └── 5.js ├── 哈希表 ├── 1078-easy-bigram分词.js ├── 1189-easy-气球的最大数量.js ├── 1287-easy-有序数组中出现次数超过25%的元素.js ├── 136-easy-只出现一次的数字.js ├── 187-medium-重复的DNA序列.js ├── 204-easy-计算质数.js ├── 219-easy-存在重复元素2.js ├── 3-medium-无重复字符的最长子串.js ├── 36-medium-有效的数独.js ├── 380-medium-常数时间插入、删除和获取随机元素.js ├── 389-easy-找不同.js ├── 409-easy-最长回文串.js ├── 454-medium-四数相加II.js ├── 500-easy-键盘行.js ├── 506-easy-相对名次.js ├── 560-medium-和为K的子数组.js ├── 575-easy-分糖果.js ├── 594-easy-最长和谐子序列.js ├── 599-easy-两个列表的最小索引总和.js ├── 645-easy-错误的集合.js ├── 648-medium-单词替换.js ├── 677-medium-键值映射.js ├── 692-medium-前K个高频单词.js ├── 706-easy-设计哈希集合.js ├── 739-medium-每日温度.js ├── 748-easy-最短完整词.js ├── 771-easy-石头与宝石.js ├── 781-medium-森林中的兔子.js ├── 811-easy-子域名访问计数.js ├── 884-easy-两句话中的不常见单词.js ├── 953-easy-验证外星语词典.js ├── 957-medium-N天后的牢房.js ├── 961-easy-重复N次的元素.js ├── 出现频率 │ ├── 347-medium-前K个高频元素.js │ └── 451-medium-根据字符出现频率排序.js ├── 同构字符串 │ ├── 205-easy-同构字符串.js │ ├── 290-easy-单词规律.js │ └── 890-medium-查找和替换模式.js ├── 字母异位词 │ ├── 242-easy-有效的字母异位词.js │ ├── 438-easy-找到字符串中的所有字母异位词.js │ └── 49-medium-字母异位词分组.js └── 并查集 │ ├── 547-medium-朋友圈.js │ └── 684-medium-冗余连接.js ├── 哈希表题目.md ├── 字符串 ├── 1016-medium-子串能表示从1到N数字的二进制串.js ├── 1041-easy-困于环中的机器人.js ├── 1071-easy-字符串的最大公因子.js ├── 1079-medium-活字印刷.js ├── 1108-easy-IP地址无效化.js ├── 1170-easy-比较字符串最小字母出现频次.js ├── 1221-easy-分割平衡字符串.js ├── 125-easy-验证回文串.js ├── 13-easy-罗马数字转整数.js ├── 1309-easy-解码字母到整数映射.js ├── 1324-medium-竖直打印单词.js ├── 1347-medium-制造字母异位词的最小步骤数.js ├── 1370.-easy-上升下降字符串.js ├── 1374.-easy-生成每种字符都是奇数个的字符串.js ├── 14-easy-最长公共前缀.js ├── 151-medium-翻转字符串里的单词.js ├── 165-medium-版本号.js ├── 28-easy-实现strStr.js ├── 299-easy-猜数字游戏.js ├── 3-noRepeatCharLongestSubStr.js ├── 344-反转字符串.js ├── 38-easy-报数.js ├── 383-赎金信.js ├── 387-easy-字符串中的第一个唯一字符.js ├── 392-easy-判断子序列.js ├── 415-easy-字符串相加.js ├── 434-easy-字符串中的单词数.js ├── 443-easy-压缩字符串.js ├── 459-easy-重复的子字符串.js ├── 482-easy-秘钥格式化.js ├── 5-medium-最长回文串.js ├── 520-检测大写字母.js ├── 521-最长特殊序列.js ├── 5377-medium-将二进制表示减到 1 的步骤数.js ├── 5380-easy-数组中的字符串匹配.js ├── 5385-medium-改变一个整数能得到的最大差值.js ├── 5386-medium-检查一个字符串是否可以打破另一个字符串.js ├── 539-medium-最小时间差.js ├── 5392-easy-分割字符串的最大得分.js ├── 5396-easy-连续字符.js ├── 541-easy-反转字符串2.js ├── 5416-easy-检查单词是否为句中其他单词的前缀.js ├── 5472-easy-重新排列字符串.js ├── 551-easy-学生出勤记录1.js ├── 553-最优除法.js ├── 557-反转字符串中的单词.js ├── 58-最后一个单词长度.js ├── 6-medium-z形变换.js ├── 657-easy-机器人能否返回原点.js ├── 680-easy-验证回文字符串2.js ├── 680-easy-验证回文字符串Ⅱ.js ├── 686-easy-重复叠加字符串匹配.js ├── 7-easy-整数反转.js ├── 709-easy-转换成小写字母.js ├── 76-hard-最小覆盖子串.js ├── 763-medium-划分字母区间.js ├── 788-旋转数字.js ├── 796-easy-旋转字符串.js ├── 804-easy-唯一摩尔斯密码词.js ├── 819-easy-最常见的单词.js ├── 824-easy-山羊拉丁文.js ├── 859-easy-亲密字符串.js ├── 917-仅仅反转字母.js ├── 929-easy-独特的电子邮件地址.js ├── 942-easy-增减字符串匹配.js └── lc-longestCommonPrefix.js ├── 字符串题目.md ├── 排序 ├── 1333-medium-餐厅过滤器.js ├── 1366-medium-通过投票对团队排名.js ├── 406.-medium-根据身高重建队列.js ├── 5350-medium-将整数按权重排序.js └── 846-medium-一手顺子.js ├── 数学类 ├── 1018-easy-可被 5 整除的二进制前缀.js ├── 1025-easy-除数博弈.js ├── 1037-easy-有效的回旋镖.js ├── 1154-easy-一年中的第几天.js ├── 1184-easy-公交站间的距离.js ├── 1185-easy-一周中的第几天.js ├── 1227-medium-飞机座位分配概率.js ├── 1266-easy-访问所有点的最小时间.js ├── 1281-easu-整数的各位积和之差.js ├── 1304.-easy-和为零的N个唯一整数.js ├── 1317-easy-将整数转换为两个无零整数的和.js ├── 1323-easy-6和9组成的最大数字.js ├── 1362-medium-最接近的因数.js ├── 1363-hard-形成三的最大倍数.js ├── 168-easy-excel列名称.js ├── 171-excel中的列序号.js ├── 172-easy-阶乘后的零.js ├── 202-easy-快乐数.js ├── 223-矩形面积.js ├── 231-easy-2的幂.js ├── 258-easy-各位相加.js ├── 263-easy-丑数.js ├── 279-完全平方数.js ├── 292-easy-nim游戏.js ├── 326-easy-3的幂.js ├── 367-easy-有效的完全平方数.js ├── 412-easy-Fizz Buzz.js ├── 453-easy-最小移动次数使数组元素相等.js ├── 492-easy-构造矩形.js ├── 507-easy-完美数.js ├── 5178-medium-四因数.js ├── 5397-medium-最简分数.js ├── 5433-medium-n 的第 k 个因子.js ├── 5452-easy-判断能否形成等差数列.js ├── 593-medium-有效的正方形.js ├── 6166-medium-最大回文数字.js ├── 633-easy-平方数之和.js ├── 67-easy-二进制求和.js ├── 670-medium-最大交换.js ├── 69-easy-x的平方根.js ├── 717-easy-1比特与2比特字符.js ├── 728-easy-自除数.js ├── 8-medium-字符串转换整数.js ├── 812-easy-最大三角形面积.js ├── 836-easy-矩形重叠.js ├── 877-medium-石子游戏.js ├── 883-easy-三维形体投影面积.js ├── 9-easy-回文数.js ├── 976-easy-三角形最大周长.js ├── 991-medium-坏了的计算器.js └── lcp2-easy-分式化简.js ├── 数学类题目.md ├── 数组类 ├── 1002-findChar.js ├── 1512-easy-好数对的数目.js ├── 605-flower.js ├── sortedArr │ ├── 154-hard-寻找旋转排序数组中的最小值 II .js │ ├── 167-easy-两数之和 II - 输入有序数组.js │ ├── 228-medium-汇总区间.js │ ├── 26-delSortedArrDupItem.js │ ├── 278-easy-第一个错误的版本.js │ ├── 34-medium-在排序数组中查找元素的第一个和最后一个位置.js │ ├── 35-searchInsertPos.js │ ├── 495-medium-提莫攻击.js │ ├── 540-medium-有序数组中的单一元素.js │ ├── 80-medium-删除排序数组中的重复项2.js │ └── 977-squareSortedArr.js ├── unSortedArr │ ├── 1-easy-两数之和.js │ ├── 1005-easy-K次取反后最大化的数组和.js │ ├── 1010-easy-总持续时间可被 60 整除的歌曲.js │ ├── 1013-divide3PartSumEqual.js │ ├── 1014-medium-最佳观光组合.js │ ├── 1029-easy-两地调度.js │ ├── 1051-heightCheck.js │ ├── 1089-easy-复写0.js │ ├── 1122-easy-数组的相对排序.js │ ├── 1122-medium-最接近原点的K个点.js │ ├── 1160-easy-拼写单词.js │ ├── 1169-easy-查询无效交易.js │ ├── 1200-easy-最小绝对差.js │ ├── 121-easy-买卖股票的最佳时机.js │ ├── 1217-easy-玩筹码.js │ ├── 122-easy-买卖股票的最佳时机2.js │ ├── 1232-easy-缀点成线.js │ ├── 1248-medium-统计「优美子数组」.js │ ├── 1282-medium-用户分组.js │ ├── 1295-easy-统计位数为偶数的数字.js │ ├── 1299-easy-将每个元素替换为右侧最大元素.js │ ├── 1310-medium-子数组异或查询.js │ ├── 1313-easy-解压缩编码列表.js │ ├── 1338-medium-数组大小减半.js │ ├── 1343-medium-大小为 K 且平均值大于等于阈值的子数组数目.js │ ├── 1365-easy-有多少小于当前数字的数字.js │ ├── 1375-medium-灯泡开关 III.js │ ├── 1475-easy-商品折扣后的最终价格.js │ ├── 153-medium-寻找旋转排序数组中的最小值.js │ ├── 1588-easy-所有奇数长度子数组的和.js │ ├── 16-medium-最接近的三数之和.js │ ├── 164-hard-最大间距.js │ ├── 169-easy-求众数.js │ ├── 1725-easy-可以形成最大正方形的矩形数目.js │ ├── 1726-medium-同积元组.js │ ├── 179-medium-最大数.js │ ├── 18-medium-四数之和.js │ ├── 189-easy-旋转数组.js │ ├── 209-medium-长度最小子数组.js │ ├── 216-medium-组合总和3.js │ ├── 217-isDepArr.js │ ├── 229-medium-求众数2.js │ ├── 268-missingNumber.js │ ├── 27-removeItem.js │ ├── 274-easy-H指数.js │ ├── 283-moveZero.js │ ├── 287-medium-寻找重复数.js │ ├── 31-medium-下一个排列.js │ ├── 315-hard-计算右侧小于当前元素的个数.js │ ├── 318-medium-最大单词长度乘积.js │ ├── 319-medium-灯泡开关.js │ ├── 398-medium-随机数索引.js │ ├── 42-hard-接雨水.js │ ├── 442-medium-数组中重复的数据.js │ ├── 448-easy-找到所有数组中消失的数字.js │ ├── 462-medium-最少移动次数使数组元素相等 II.js │ ├── 503-medium-下一个更大元素2.js │ ├── 5185-easy-存在连续三个奇数的数组.js │ ├── 5205-easy-独一无二的出现次数.js │ ├── 532-easy-数组中的K-diff数对.js │ ├── 5349-medium-安排电影院座位.js │ ├── 5360-easy-统计最大组的数目.js │ ├── 5364-easy-按既定顺序创建目标数组.js │ ├── 5368-easy-找出数组中的幸运数.js │ ├── 5369-medium-统计作战单位数.js │ ├── 5381-medium-查询带键的排列.js │ ├── 5384-easy-拥有最多糖果的孩子.js │ ├── 5393-medium-可获得的最大点数.js │ ├── 5394-medium-对角线遍历 II.js │ ├── 5400-easy-旅行终点站.js │ ├── 5401-medium-是否所有 1 都至少相隔 k 个元素.js │ ├── 5402-medium-绝对差不超过限制的最长连续子数组.js │ ├── 5408-easy-通过翻转子数组使两个数组相等.js │ ├── 5424-easy-数组中两元素的最大乘积.js │ ├── 5425-medium-切割后面积最大的蛋糕.js │ ├── 5428-easy-重新排列数组.js │ ├── 5432-easy-去掉最低工资和最高工资后的工资平均值.js │ ├── 5434-medium-删掉一个元素以后全为 1 的最长子数组.js │ ├── 5445-medium-子数组和排序后的区间和.js │ ├── 5475-easy-统计好三元组.js │ ├── 5488-medium-使数组中所有元素相等的最小操作数.js │ ├── 56-medium-合并区间.js │ ├── 561-deArr.js │ ├── 605-easy-种花问题.js │ ├── 628-3itemMultiMax.js │ ├── 643-easy子数组最大平均数I.js │ ├── 66-add1.js │ ├── 665-easy-非递减数列.js │ ├── 682-easy-棒球比赛.js │ ├── 697-arrayDegree.js │ ├── 714-medium-买卖股票的最佳时机含手续费.js │ ├── 724-easy-寻找数组的中心索引.js │ ├── 75-medium-颜色分类.js │ ├── 775-medium-全局倒置和局部倒置.js │ ├── 78-medium-子集.js │ ├── 806-easy写字符串需要的行数.js │ ├── 821-easy-字符的最短距离.js │ ├── 830-easy-较大分组的位置.js │ ├── 849-easy-到最近的人的最近距离.js │ ├── 852-easy-山脉数组的峰顶索引.js │ ├── 860-easy-柠檬水找零.js │ ├── 867-translateMatrix.js │ ├── 896-easy-单调数列.js │ ├── 905-sortArrByOddAndEven.js │ ├── 912-medium-排序数组.js │ ├── 914-easy-卡牌分组.js │ ├── 915-medium-分割数组.js │ ├── 922-sortByOddAndEven.js │ ├── 941-easy-有效的山脉数组.js │ ├── 944-easy-删列造序.js │ ├── 945-medium-使数组唯一的最小增量.js │ ├── 989-easy-.js │ ├── 989-easy-数组形式的整数加法.js │ └── 997-easy-找到小镇的法官.js ├── 前缀和 │ ├── 1480-easy-一维数组的动态和.js │ ├── 303-easy-区域和检索 - 数组不可变.js │ ├── 307-medium-区域和检索 - 数组可修改.js │ ├── 525-medium-连续数组.js │ └── 848-medium-字母移位.js ├── 多个数组 │ ├── 5348-easy-两个数组间的距离值.js │ ├── 832-reverseImage.js │ ├── 88-mergeTwoSortedArr.js │ ├── 888-easy-公平的糖果交换.js │ ├── 985-easy-查询后的偶数和.js │ └── LCP1-easy-猜数字.js ├── 多维数组 │ ├── 1030-easy-距离顺序排序矩阵单元格.js │ ├── 118-easy-杨辉三角1.js │ ├── 119-easy-杨辉三角2.js │ ├── 1252-easy-奇数值单元格的数目.js │ ├── 1260-easy-二维网格迁移.js │ ├── 1351-easy-统计有序矩阵中的负数.js │ ├── 1476-medium-子矩形查询.js │ ├── 1572-easy-矩阵对角线元素的和.js │ ├── 1672-easy-最富有客户的资产总量.js │ ├── 289-medium-生命游戏.js │ ├── 378-medium-有序矩阵中第k小的元素.js │ ├── 463-easy-岛屿的周长.js │ ├── 502-medium-01矩阵.js │ ├── 5356-easy-矩阵中的幸运数.js │ ├── 54-medium-螺旋矩阵.js │ ├── 566-easy-重塑矩阵.js │ ├── 59-medium-螺旋矩阵2.js │ ├── 598-easy-范围求和2.js │ ├── 661-easy-图片平滑器.js │ ├── 73-medium-矩阵置零.js │ ├── 733-easy-图像渲染.js │ ├── 74-medium-搜索二维矩阵.js │ ├── 766-easy-托普利茨矩阵.js │ ├── 840-easy-矩阵中的幻方.js │ ├── 861-medium-翻转矩阵后的得分.js │ └── 874-easy-模拟行走机器人.js └── 约瑟夫环问题 │ └── 950-medium-按递增顺序显示卡牌.js ├── 数组题目.md ├── 日期问题 └── 1360-easy-日期之间间隔几天.js ├── 栈 ├── 1047-easy-删除字符串中的所有相邻重复项.js ├── 1124-medium-表现良好的最长时间段.js ├── 155-easy-最小栈.js ├── 20-easy-有效的括号.js ├── 225-easy-用队列实现栈.js ├── 394-medium-字符串解码.js ├── 496-easy-下一个更大元素.js ├── 503-medium-下一个更大元素2.js ├── 5357-medium-设计一个支持增量操作的栈.js ├── 844-easy-比较含退格的字符串.js ├── 921-medium-使括号有效的最少添加.js └── 946-medium-验证栈序列.js ├── 栈题目.md ├── 树 ├── 5426-medium-重新规划路线.js ├── trie │ ├── 208-medium-实现Trie.js │ └── 720-easy-词典中最长的单词.js └── 二叉树 │ ├── 100-easy-相同的树.js │ ├── 1008-medium-先序遍历构造二叉树.js │ ├── 101-easy-对称二叉树.js │ ├── 102-medium-二叉树的层序遍历.js │ ├── 1022-easy-从根到叶的二进制数之和.js │ ├── 103-medium-二叉树的锯齿形遍历.js │ ├── 104-easy-二叉树的最大深度.js │ ├── 107-easy-二叉树的层序遍历2.js │ ├── 111-easy-二叉树的最小深度.js │ ├── 112-easy-路径总和.js │ ├── 114-medium-二叉树展开成链表.js │ ├── 1161-medium-最大层内元素和.js │ ├── 129-medium-求根到叶子节点数字之和.js │ ├── 1302-medium-层数最深叶子节点的和.js │ ├── 1305-medium-两棵二叉搜索树中的所有元素.js │ ├── 1315-medium-祖父节点值为偶数的节点和.js │ ├── 1361-medium-验证二叉树.js │ ├── 1367-medium-二叉树中的列表.js │ ├── 1379-medium-找出克隆二叉树中的相同节点.js │ ├── 144-medium-二叉树的先序遍历.js │ ├── 145-hard-二叉树的后序遍历.js │ ├── 199-medium-二叉树的右视图.js │ ├── 226-easy-翻转二叉树.js │ ├── 230-medium-二叉搜索树中的第K小的元素.js │ ├── 235-easy-二叉搜索树的最近公共祖先.js │ ├── 257-easy-二叉树的所有路径.js │ ├── 404-easy-左叶子之和.js │ ├── 429-easy-N叉树的层序遍历.js │ ├── 513-medium-找树左下角的值.js │ ├── 515-medium-在每个树行中找最大值.js │ ├── 5179-medium-将二叉搜索树变平衡.js │ ├── 530-easy-二叉搜索树的最小绝对差.js │ ├── 5398-medium-统计二叉树中好节点的数目.js │ ├── 543-easy-二叉树的直径.js │ ├── 559-easy-N叉树的最大深度.js │ ├── 563-easy-二叉树的坡度.js │ ├── 589-easy-N叉树的先序遍历.js │ ├── 590-easy-N叉树的后序遍历.js │ ├── 617-easy-合并二叉树.js │ ├── 637-easy-二叉树的层平均值.js │ ├── 654-medium-最大二叉树.js │ ├── 671-easy-二叉树中第二小的节点.js │ ├── 700-easy-二叉搜索树中的搜索.js │ ├── 701-medium-二叉搜索树中的插入操作.js │ ├── 783-easy-二叉搜索树结点最小距离.js │ ├── 814-medium-二叉树剪枝.js │ ├── 872-easy-叶子相似的树.js │ ├── 938-easy-二叉搜索树的范围和.js │ ├── 94-medium-二叉树的中序遍历.js │ ├── 965-easy-单值二叉树.js │ ├── 98-medium-验证二叉搜索树.js │ └── 数据结构 │ ├── BST.js │ └── 哈夫曼树.js ├── 树题目.md ├── 正则 ├── 1023-medium-驼峰式匹配.js └── 5382-medium-HTML 实体解析器.js ├── 程序员面试金典 ├── 01.01-easy-判定字符是否唯一.js ├── 01.02-easy-判定是否互为字符重排.js ├── 01.08-medium-零矩阵.js ├── 01.09-easy-字符串轮转.js ├── 02.01-easy-移除重复节点.js ├── 02.02-easy-返回倒数第 k 个节点.js ├── 04.03-medium-特定深度节点链表.js ├── 04.06-medium-后继者.js ├── 05.01-easy-插入.js ├── 05.07-easy-.js ├── 08.01-easy-三步问题.js ├── 08.03-easy-魔术索引.js ├── 08.07-medium-无重复字符串的排列组合.js ├── 10.01-easy-合并排序的数组.js ├── 10.05-easy-稀疏数组搜索.js ├── 16.01-medium-交换数字.js ├── 16.02-medium-单词频率.js ├── 16.10-medium-生存人数.js ├── 16.11-easy-跳水板.js ├── 16.15-easy-珠玑妙算.js ├── 16.17-easy-连续数列.js ├── 16.21-medium-交换和.js ├── 16.24-medium-数对和.js ├── 16.25-medium-LRU缓存.js ├── 17.10-easy-主要元素.js ├── 17.14-medium-最小K个数.js ├── 17.16-easy-按摩师.js └── 17.19-hard-消失的两个数字.js ├── 设计 ├── 1603-easy设计停车系统.js └── 5370-medium-设计地铁系统.js ├── 贪心 ├── 376-medium-摇摆序列.js ├── 455-easy-分发饼干.js ├── 5376-easy-非递增顺序的最小子序列.js └── 55-medium-跳跃游戏.js ├── 趣味题 └── 两个数表示三个数.js ├── 递归 ├── 1046-easy-最后一块石头的重量.js ├── 1137-easy-第 N 个泰波那契数.js ├── 1209-medium-删除字符串中的所有相邻重复项II.js └── 509-fibna.js ├── 链表 ├── 1019-medium-链表中的下一个更大节点.js ├── 141-easy-环形链表.js ├── 142-medium-环形链表2.js ├── 160-easy-相交链表.js ├── 19-medium-删除链表的倒数第N个节点.js ├── 2-medium-两数相加.js ├── 203-easy-移除链表元素.js ├── 206-easy-反转链表.js ├── 21-easy-合并两个有序链表.js ├── 237-easy-删除链表中的节点.js ├── 24-medium-两两交换链表中的节点.js ├── 445-medium-两数相加2.js ├── 5283-easy-二进制链表转整数.js ├── 61-medium-旋转链表.js ├── 707-easy-设计链表.js ├── 817-medium-链表组件.js ├── 82-medium-删除排序链表中的重复元素2.js └── 83-easy-删除排序链表中的重复元素.js ├── 链表题目.md ├── 队列 ├── 232-easy-用栈实现队列.js ├── 933-easy-最近的请求次数.js ├── 优先队列 │ ├── 414-easy-第三大的数.js │ └── priorityQueue.js └── 单调队列 │ └── 239-hard-滑动窗口最大值.js └── 面试题 └── 二维数组回形遍历.js /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/.gitignore -------------------------------------------------------------------------------- /.idea/branin-model-tool.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DFS.md: -------------------------------------------------------------------------------- 1 | ## 深度优先搜素 2 | 3 | * 17 medium 电话号码的字母组合 4 | * 22 medium 括号生成 5 | * 39 medium 组合总和 6 | * 40 medium 组合总和2 7 | * 46 medium 全排列 8 | * 47 medium 全排列2 9 | * 77 medium 组合 10 | * 90 medium 子集2 11 | * 200 medium 岛屿数量 12 | * 216 medium 组合总和3 13 | * 494 medium 目标和 14 | * 695 medium 岛屿的最大面积 15 | * 784 easy 字母大小写全排列 16 | * 841 medium 钥匙和房间 17 | * 1020 medium 飞地的数量 18 | * 1376 medium 通知所有员工所需的时间 19 | -------------------------------------------------------------------------------- /DFS/1239-medium-串联字符串的最大长度.js: -------------------------------------------------------------------------------- 1 | //1239. 串联字符串的最大长度 medium 2 | 3 | // 给定一个字符串数组 arr,字符串 s 是将 arr 某一子序列字符串连接所得的字符串,如果 s 中的每一个字符都只出现过一次, 4 | // 那么它就是一个可行解。 5 | // 请返回所有可行解 s 中最长长度。 6 | //   7 | // 示例 1: 8 | // 输入:arr = ["un","iq","ue"] 9 | // 输出:4 10 | // 解释:所有可能的串联组合是 "","un","iq","ue","uniq" 和 "ique",最大长度为 4。 11 | // 示例 2: 12 | // 输入:arr = ["cha","r","act","ers"] 13 | // 输出:6 14 | // 解释:可能的解答有 "chaers" 和 "acters"。 15 | // 示例 3: 16 | // 输入:arr = ["abcdefghijklmnopqrstuvwxyz"] 17 | // 输出:26 18 | //   19 | // 提示: 20 | // 1 <= arr.length <= 16 21 | // 1 <= arr[i].length <= 26 22 | // arr[i] 中只含有小写英文字母 23 | 24 | -------------------------------------------------------------------------------- /DFS/17-medium-电话号码的字母组合.js: -------------------------------------------------------------------------------- 1 | // 17 medium 电话号码的字母组合 2 | 3 | // 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 4 | // 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 5 | // 6 | // 7 | // 8 | // 示例: 9 | // 输入:"23" 10 | // 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 11 | // 说明: 12 | // 尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。 13 | // 14 | 15 | 16 | /** 17 | * @param {string} digits 18 | * @return {string[]} 19 | */ 20 | var letterCombinations = function(digits) { 21 | if(!digits)return [] 22 | let chars = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']; 23 | let s = [''] 24 | for (let i = 0; i < digits.length; i++){ 25 | let number = digits[i] / 1; 26 | let sNew = [] 27 | for (let k = 0; k < s.length; k++){ 28 | for (let j = 0; j < chars[number].length; j++){ 29 | sNew.push(s[k] + chars[number][j]) 30 | } 31 | } 32 | s = sNew 33 | } 34 | return s; 35 | }; 36 | 37 | console.log(letterCombinations('23')) -------------------------------------------------------------------------------- /DFS/22-medium-括号生成.js: -------------------------------------------------------------------------------- 1 | // 22 medium 括号生成 2 | 3 | 4 | //给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 5 | // 6 | // 例如,给出 n = 3,生成结果为: 7 | // 8 | // [ 9 | // "((()))", 10 | // "(()())", 11 | // "(())()", 12 | // "()(())", 13 | // "()()()" 14 | // ] 15 | // 16 | 17 | 18 | var bracket = (n) => { 19 | let result = [] 20 | // 递归共有两个出口,合法出口 和 不合法出口。 21 | let dfs = (left, right, str, result) => { 22 | // 右括号多于左括号, 比如)))((, 这种情况,必然不合法 23 | if (left > right) {return;} 24 | else if (left === 0 && right === 0){ 25 | // 合法出口 26 | result.push(str) 27 | }else { 28 | // 需要继续递归下去的情况 29 | if (left > 0){ 30 | dfs(left - 1, right, str + '(', result); 31 | } 32 | if (right > 0){ 33 | dfs(left, right - 1, str + ')', result); 34 | } 35 | } 36 | } 37 | dfs(n, n, '', result); 38 | return result; 39 | } 40 | console.log(bracket(3)) -------------------------------------------------------------------------------- /DFS/377-medium-组合总和4.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * @param {number[]} nums 6 | * @param {number} target 7 | * @return {number} 8 | */ 9 | var combinationSum4 = function(nums, target) { 10 | 11 | }; 12 | 13 | // console.log(combinationSum4([1,2,3], 4)) 14 | console.log(combinationSum4([4,2,1],32)) -------------------------------------------------------------------------------- /DFS/46-medium-全排列.js: -------------------------------------------------------------------------------- 1 | // 46 medium 全排列 2 | 3 | // 给定一个没有重复数字的序列,返回其所有可能的全排列。 4 | // 5 | // 示例: 6 | // 输入: [1,2,3] 7 | // 输出: 8 | // [ 9 | // [1,2,3], 10 | // [1,3,2], 11 | // [2,1,3], 12 | // [2,3,1], 13 | // [3,1,2], 14 | // [3,2,1] 15 | // ] 16 | 17 | 18 | /** 19 | * @param {number[]} nums 20 | * @return {number[][]} 21 | */ 22 | let fn = (nums) => { 23 | let ans = []; 24 | let hash = []; 25 | let path = []; 26 | let dfs = (idx, nums) => { 27 | if(idx === nums.length) { 28 | ans.push([...path]); 29 | return; 30 | } 31 | for (let i = 0; i < nums.length; i++){ 32 | if(hash[i]) continue; 33 | path.push(nums[i]); 34 | hash[i] = true; // 表示是否往res放过的哈希 35 | dfs(idx + 1, nums); 36 | hash[i] = false; 37 | path.pop(); 38 | } 39 | } 40 | dfs( 0, nums); 41 | return ans; 42 | } -------------------------------------------------------------------------------- /DFS/90-medium-子集2.js: -------------------------------------------------------------------------------- 1 | // 90 medium 子集2 2 | 3 | //给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 4 | // 5 | // 说明:解集不能包含重复的子集。 6 | // 7 | // 示例: 8 | // 9 | // 输入: [1,2,2] 10 | // 输出: 11 | // [ 12 | // [2], 13 | // [1], 14 | // [1,2,2], 15 | // [2,2], 16 | // [1,2], 17 | // [] 18 | // ] 19 | // 20 | 21 | 22 | 23 | var subsetsWithDup = (nums) => { 24 | if(!nums.length) return []; 25 | nums.sort((a, b) => { 26 | return a - b; 27 | }) 28 | let ans = [[], [nums[0]]]; 29 | let hash = {[nums[0]]: true} 30 | for (let i = 1; i < nums.length; i++){ 31 | let arr = [] 32 | for (let j = 0; j < ans.length; j++){ 33 | let tmpArr = [...ans[j]]; 34 | tmpArr.push(nums[i]) 35 | if(hash[tmpArr.join('')])continue; // 去重 36 | arr.push(tmpArr); 37 | hash[tmpArr.join('')] = true; 38 | } 39 | ans = ans.concat(arr); 40 | } 41 | return ans; 42 | } 43 | console.log(subsetsWithDup([1,2,2])) -------------------------------------------------------------------------------- /img/fe-algo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/img/fe-algo.jpeg -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | LeetCode刷题仓库 2 | 3 | 前端算法库:https://github.com/cunzaizhuyi/js-leetcode 4 | 这里记录了我刷过的500多道LeetCode的题解, 5 | 希望对前端同行找工作面试、修炼算法内功有帮助。 6 | 7 | 8 | 9 | 另外,刷题之前,先看下经典数据结构与算法的js实现是很重要的。我把它拆分到了另一个仓库里。 10 | [js实现经典数据结构与算法地址](https://github.com/cunzaizhuyi/ds-algorithm) 11 | 12 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/test.js -------------------------------------------------------------------------------- /test2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/test2.js -------------------------------------------------------------------------------- /二分查找.md: -------------------------------------------------------------------------------- 1 | ## 二分查找 2 | 3 | * 33 medium 搜索旋转排序数组 4 | * 81 medium 搜索旋转排序数组2 5 | * 162 medium 寻找峰值 6 | * 240 medium 搜索二维矩阵2 7 | * 275 medium h指数2 8 | * 441 easy 排列硬币 9 | * 704 easy 二分查找 10 | * 744 easy 寻找比目标字母大的最小字母 -------------------------------------------------------------------------------- /二分查找/162-medium-寻找峰值.js: -------------------------------------------------------------------------------- 1 | // 162. 寻找峰值 medium 2 | 3 | // 峰值元素是指其值大于左右相邻值的元素。 4 | // 给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。 5 | // 数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。 6 | // 你可以假设 nums[-1] = nums[n] = -∞。 7 | // 8 | // 示例 1: 9 | // 输入: nums = [1,2,3,1] 10 | // 输出: 2 11 | // 解释: 3 是峰值元素,你的函数应该返回其索引 2。 12 | // 示例 2: 13 | // 输入: nums = [1,2,1,3,5,6,4] 14 | // 输出: 1 或 5 15 | // 解释: 你的函数可以返回索引 1,其峰值元素为 2; 16 | //   或者返回索引 5, 其峰值元素为 6。 17 | // 说明: 18 | // 你的解法应该是 O(logN) 时间复杂度的。 19 | // 20 | 21 | /** 22 | * @param {number[]} nums 23 | * @return {number} 24 | */ 25 | var findPeakElement = function(nums) { 26 | if(nums.length === 1) return 0; 27 | let l = 0; 28 | let r = nums.length - 1; 29 | while(l <= r){ 30 | let mid = ~~((l + r) / 2); 31 | if(nums[mid] < nums[mid + 1]){ 32 | l = mid + 1; 33 | }else{ 34 | r = mid - 1; 35 | } 36 | } 37 | return l; 38 | }; 39 | 40 | console.log(findPeakElement([1,2,3,1])) 41 | console.log(findPeakElement([1,2,1,3,5,6,4])) -------------------------------------------------------------------------------- /二分查找/441-easy-排列硬币.js: -------------------------------------------------------------------------------- 1 | // 441 easy 排列硬币 2 | 3 | // 你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。 4 | // 给定一个数字 n,找出可形成完整阶梯行的总行数。 5 | // n 是一个非负整数,并且在32位有符号整型的范围内。 6 | // 7 | // 示例 1: 8 | // n = 5 9 | // 10 | // 硬币可排列成以下几行: 11 | // ¤ 12 | // ¤ ¤ 13 | // ¤ ¤ 14 | // 15 | // 因为第三行不完整,所以返回2. 16 | // 示例 2: 17 | // n = 8 18 | // 硬币可排列成以下几行: 19 | // ¤ 20 | // ¤ ¤ 21 | // ¤ ¤ ¤ 22 | // ¤ ¤ 23 | // 24 | // 因为第四行不完整,所以返回3. 25 | 26 | 27 | /** 28 | * 不用二分 29 | * @param {number} n 30 | * @return {number} 31 | */ 32 | var arrangeCoins = function(n) { 33 | if(n ===0) return 0; 34 | 35 | // 假设结果为K 36 | for(let i = 1; i <= n; i++){ 37 | if (n >= (1+i)* (i)/ 2 && n < ((1+i+1) * (i +1)) / 2){ 38 | return i; 39 | } 40 | } 41 | }; 42 | 43 | console.log(arrangeCoins(5)) -------------------------------------------------------------------------------- /二分查找/81-medium-搜索旋转排序数组2.js: -------------------------------------------------------------------------------- 1 | // 81 medium 搜索旋转排序数组2 2 | 3 | //假设按照升序排序的数组在预先未知的某个点上进行了旋转。 4 | // 5 | // ( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。 6 | // 7 | // 编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。 8 | // 9 | // 示例 1: 10 | // 输入: nums = [2,5,6,0,0,1,2], target = 0 11 | // 输出: true 12 | // 示例 2: 13 | // 输入: nums = [2,5,6,0,0,1,2], target = 3 14 | // 输出: false 15 | // 进阶: 16 | // 这是 搜索旋转排序数组 的延伸题目,本题中的 nums  可能包含重复元素。 17 | // 这会影响到程序的时间复杂度吗?会有怎样的影响,为什么? 18 | // 19 | 20 | 21 | /** 22 | * 不用二分,复杂度较高,O(n) 23 | * @param {number[]} nums 24 | * @param {number} target 25 | * @return {boolean} 26 | */ 27 | var search = function(nums, target) { 28 | return nums.indexOf(target) !== -1; 29 | }; 30 | -------------------------------------------------------------------------------- /位运算.md: -------------------------------------------------------------------------------- 1 | ## 位运算 2 | 3 | * 137 medium 只出现一次的元素2 4 | * 191 easy 位1的个数 5 | * 260 medium只出现一次的数字3 6 | * -338 medium 比特位计数 7 | * 461 easy 汉明距离 8 | * 476 easy 数字的补数 9 | * 477 medium 汉明距离总和 10 | * 693 easy 交替位二进制数 11 | * 762 easy 二进制表示中质数个计算置位 12 | * 784 easy 字母大小写全排列 13 | * 1318 medium 或运算的最小翻转次数 -------------------------------------------------------------------------------- /位运算/137-medium-只出现一次的元素2.js: -------------------------------------------------------------------------------- 1 | // 137 medium 只出现一次的元素2 2 | // 3 | // 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。 4 | // 5 | // 说明: 6 | // 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 7 | // 8 | // 示例 1: 9 | // 输入: [2,2,3,2] 10 | // 输出: 3 11 | 12 | // 示例 2: 13 | // 输入: [0,1,0,1,0,1,99] 14 | // 输出: 99 15 | 16 | 17 | /** 18 | * @param {number[]} nums 19 | * @return {number} 20 | */ 21 | var singleNumber = function(nums) { 22 | let hash = {} 23 | for(let i = 0; i < nums.length; i++){ 24 | if(!hash[nums[i]]) hash[nums[i]] = 1; 25 | else { 26 | hash[nums[i]]++; 27 | } 28 | } 29 | 30 | let arr = [] 31 | for(let key in hash){ 32 | if(hash[key] === 1) { 33 | return Number(key) 34 | } 35 | } 36 | }; 37 | 38 | 39 | console.log(singleNumber([2,2,3,2])) -------------------------------------------------------------------------------- /位运算/1486-easy-数组异或操作.js: -------------------------------------------------------------------------------- 1 | 2 | //1486. 数组异或操作 easy 3 | 4 | // 给你两个整数,n 和 start 。 5 | // 数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。 6 | // 请返回 nums 中所有元素按位异或(XOR)后得到的结果。 7 | // 8 | // 9 | // 示例 1: 10 | // 输入:n = 5, start = 0 11 | // 输出:8 12 | // 解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。 13 | // "^" 为按位异或 XOR 运算符。 14 | // 示例 2: 15 | // 输入:n = 4, start = 3 16 | // 输出:8 17 | // 解释:数组 nums 为 [3, 5, 7, 9],其中 (3 ^ 5 ^ 7 ^ 9) = 8. 18 | // 示例 3: 19 | // 输入:n = 1, start = 7 20 | // 输出:7 21 | // 示例 4: 22 | // 输入:n = 10, start = 5 23 | // 输出:2 24 | // 25 | // 提示: 26 | // 1 <= n <= 1000 27 | // 0 <= start <= 1000 28 | // n == nums.length 29 | 30 | 31 | 32 | var xorOperation = function(n, start) { 33 | let nums = [] 34 | for(let i = 0; i < n; i++){ 35 | nums[i] = start + 2 * i; 36 | } 37 | let a = nums[0] 38 | for(let i = 1; i < nums.length; i++){ 39 | a = a^nums[i] 40 | } 41 | return a; 42 | }; 43 | -------------------------------------------------------------------------------- /位运算/190-easy-颠倒二进制位.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {number} n - a positive integer 5 | * @return {number} - a positive integer 6 | */ 7 | var reverseBits = function(n) { 8 | let bin = n.toString(2).split('') 9 | // let l = 0, r = bin.length - 1; 10 | // while(l < r){ 11 | // [bin[r], bin[l]] = [bin[l], bin[r]]; 12 | // l++; 13 | // r--; 14 | // } 15 | bin.reverse() 16 | return parseInt(bin.join(''), 2) 17 | 18 | }; 19 | 20 | console.log(reverseBits('00000010100101000001111010011100')) 21 | // console.log(reverseBits('11111111111111111111111111111101')) -------------------------------------------------------------------------------- /位运算/210-medium-数字范围按位与.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 超时 4 | * @param {number} m 5 | * @param {number} n 6 | * @return {number} 7 | */ 8 | var rangeBitwiseAnd = function(m, n) { 9 | if(m === n) return n; 10 | let res = m; 11 | for(let i = m+1; i <= n; i++){ 12 | res &= i; 13 | } 14 | return res 15 | }; 16 | 17 | 18 | var rangeBitwiseAnd2 = function(m, n) { 19 | if(m === n) return n; 20 | let res = m; 21 | for(let i = m+1; i <= n; i++){ 22 | res &= i; 23 | } 24 | return res 25 | }; 26 | 27 | console.log(rangeBitwiseAnd2(0,1)) 28 | -------------------------------------------------------------------------------- /位运算/260-medium-只出现一次的数字3.js: -------------------------------------------------------------------------------- 1 | // 260 medium 只出现一次的数字3 2 | 3 | // 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。 4 | // 5 | // 示例 : 6 | // 输入: [1,2,1,3,2,5] 7 | // 输出: [3,5] 8 | 9 | // 注意: 10 | // 结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。 11 | // 你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现? 12 | 13 | 14 | 15 | /** 16 | * @param {number[]} nums 17 | * @return {number[]} 18 | */ 19 | var singleNumber = function(nums) { 20 | let hash = {} 21 | for(let i = 0; i < nums.length; i++){ 22 | if(!hash[nums[i]]) hash[nums[i]] = 1; 23 | else { 24 | hash[nums[i]]++; 25 | } 26 | } 27 | 28 | let arr = [] 29 | for(let key in hash){ 30 | if(hash[key] === 1) { 31 | arr.push(Number(key)) 32 | } 33 | } 34 | return arr; 35 | }; 36 | 37 | console.log(singleNumber([1,2,1,3,2,5])) -------------------------------------------------------------------------------- /位运算/338-medium-比特位计数.js: -------------------------------------------------------------------------------- 1 | // 338 medium 比特位计数 2 | 3 | // 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 4 | // 5 | // 示例 1: 6 | // 输入: 2 7 | // 输出: [0,1,1] 8 | 9 | // 示例 2: 10 | // 输入: 5 11 | // 输出: [0,1,1,2,1,2] 12 | 13 | // 进阶: 14 | // 给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗? 15 | // 要求算法的空间复杂度为O(n)。 16 | // 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。 17 | 18 | 19 | 20 | /** 21 | * 奇偶性规律 22 | * @param {number} num 23 | * @return {number[]} 24 | */ 25 | var countBits = function(num) { 26 | let arr = [0] // 0的比特位为1的数是0个 27 | for(let i = 1; i <= num; i++){ 28 | if (i % 2 === 1){ // 奇数 29 | arr.push(arr[i-1] + 1) // 前面那个偶数的最末位加1 30 | 31 | } else { // 偶数 32 | arr.push(arr[i / 2]) // 跟 是它一半的那个数 的1一样多 33 | } 34 | } 35 | return arr; 36 | }; 37 | 38 | console.log(countBits(2)) -------------------------------------------------------------------------------- /位运算/342-easy-4的幂.js: -------------------------------------------------------------------------------- 1 | // 342 easy 4的幂 2 | 3 | // 给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。 4 | // 5 | // 示例 1: 6 | // 输入: 16 7 | // 输出: true 8 | 9 | // 示例 2: 10 | // 输入: 5 11 | // 输出: false 12 | // 进阶: 13 | // 你能不使用循环或者递归来完成本题吗? 14 | 15 | 16 | /** 17 | * @param {number} num 18 | * @return {boolean} 19 | */ 20 | var isPowerOfFour = function(num) { 21 | if(num === 1) return true; 22 | while(num > 3){ 23 | num = num / 4; 24 | } 25 | if(num === 1) return true 26 | else{ 27 | return false 28 | } 29 | }; 30 | 31 | console.log(isPowerOfFour(4)) -------------------------------------------------------------------------------- /位运算/397-medium-整数替换.js: -------------------------------------------------------------------------------- 1 | //397 medium 整数替换 2 | 3 | // 给定一个正整数 n,你可以做如下操作: 4 | // 5 | // 1. 如果 n 是偶数,则用 n / 2替换 n。 6 | // 2. 如果 n 是奇数,则可以用 n + 1或n - 1替换 n。 7 | // n 变为 1 所需的最小替换次数是多少? 8 | // 9 | // 示例 1: 10 | // 输入: 11 | // 8 12 | // 输出: 13 | // 3 14 | // 解释: 15 | // 8 -> 4 -> 2 -> 1 16 | 17 | // 示例 2: 18 | // 输入: 19 | // 7 20 | // 输出: 21 | // 4 22 | // 解释: 23 | // 7 -> 8 -> 4 -> 2 -> 1 24 | // 或 25 | // 7 -> 6 -> 3 -> 2 -> 1 26 | 27 | 28 | /** 29 | * @param {number} n 30 | * @return {number} 31 | */ 32 | var integerReplacement = function(n) { 33 | if (n === 1) return 0 34 | if(n%2===0){ 35 | return 1 + integerReplacement(n / 2) 36 | }else{ 37 | return 1 + Math.min(integerReplacement(n-1), integerReplacement(n+1)) 38 | } 39 | 40 | }; 41 | 42 | // console.log(integerReplacement(7)) 43 | // console.log(integerReplacement(8)) 44 | // console.log(integerReplacement(65535)) 45 | console.log(integerReplacement(10000)) -------------------------------------------------------------------------------- /位运算/476-easy-数字的补数.js: -------------------------------------------------------------------------------- 1 | // 476 easy 数字的补数 2 | 3 | // 给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。 4 | // 5 | // 注意: 6 | // 给定的整数保证在32位带符号整数的范围内。 7 | // 你可以假定二进制数不包含前导零位。 8 | 9 | // 示例 1: 10 | // 输入: 5 11 | // 输出: 2 12 | // 解释: 5的二进制表示为101(没有前导零位),其补数为010。所以你需要输出2。 13 | 14 | // 示例 2: 15 | // 输入: 1 16 | // 输出: 0 17 | // 解释: 1的二进制表示为1(没有前导零位),其补数为0。所以你需要输出0。 18 | 19 | 20 | 21 | /** 22 | * @param {number} num 23 | * @return {number} 24 | */ 25 | var findComplement = function(num) { 26 | let b = num.toString(2) 27 | let arr = [] 28 | for(let i = 0; i < b.length; i++){ 29 | arr[i] = b[i] === '1' ? '0': '1' 30 | } 31 | let s = arr.join('') 32 | return parseInt(s, 2) 33 | }; 34 | 35 | console.log(findComplement(5)) 36 | 37 | -------------------------------------------------------------------------------- /位运算/784-easy-字母大小写全排列.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {string} S 5 | * @return {string[]} 6 | */ 7 | var letterCasePermutation = function(S) { 8 | 9 | }; -------------------------------------------------------------------------------- /剑指offer/03-easy-数组中重复的数字.js: -------------------------------------------------------------------------------- 1 | // 03 easy 数组中重复的数字 2 | 3 | // 找出数组中重复的数字。 4 | // 5 | // 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。 6 | // 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 7 | // 示例 1: 8 | // 9 | // 输入: 10 | // [2, 3, 1, 0, 2, 5, 3] 11 | // 输出:2 或 3 12 | //   13 | // 限制: 14 | // 2 <= n <= 100000 15 | 16 | /** 17 | * @param {number[]} nums 18 | * @return {number} 19 | */ 20 | var findRepeatNumber = function(nums) { 21 | let hash = {}; 22 | for(let i = 0; i < nums.length; i++){ 23 | if(hash[nums[i]]) return nums[i]; 24 | hash[nums[i]] = true; 25 | } 26 | }; -------------------------------------------------------------------------------- /剑指offer/05-easy-替换空格.js: -------------------------------------------------------------------------------- 1 | // 05 easy 替换空格 2 | 3 | // 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 4 | // 5 | // 示例 1: 6 | // 输入:s = "We are happy." 7 | // 输出:"We%20are%20happy." 8 | //   9 | // 10 | // 限制: 11 | // 0 <= s 的长度 <= 10000 12 | // 13 | 14 | var replaceSpace = function(s) { 15 | return s.replace(/\s{1}/g, '%20'); 16 | }; -------------------------------------------------------------------------------- /剑指offer/06-easy-从尾到头打印链表.js: -------------------------------------------------------------------------------- 1 | // 06 easy 从尾到头打印链表 2 | 3 | 4 | // 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 5 | // 6 | // 示例 1: 7 | // 8 | // 输入:head = [1,3,2] 9 | // 输出:[2,3,1] 10 | //   11 | // 限制: 12 | // 0 <= 链表长度 <= 10000 13 | 14 | /** 15 | * Definition for singly-linked list. 16 | * function ListNode(val) { 17 | * this.val = val; 18 | * this.next = null; 19 | * } 20 | */ 21 | /** 22 | * @param {ListNode} head 23 | * @return {number[]} 24 | */ 25 | var reversePrint = function(head) { 26 | let result = []; 27 | while(head){ 28 | result.push(head.val) 29 | head = head.next; 30 | } 31 | return result.reverse(); 32 | }; -------------------------------------------------------------------------------- /剑指offer/10-easy-斐波那契数列.js: -------------------------------------------------------------------------------- 1 | 2 | // 10 easy 斐波那契数列 3 | 4 | // 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下: 5 | // 6 | // F(0) = 0,   F(1) = 1 7 | // F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 8 | // 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。 9 | // 10 | // 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 11 | // 12 | // 13 | // 示例 1: 14 | // 输入:n = 2 15 | // 输出:1 16 | // 示例 2: 17 | // 输入:n = 5 18 | // 输出:5 19 | //   20 | // 21 | // 提示: 22 | // 0 <= n <= 100 23 | 24 | 25 | // 10 26 | var fib = function(n) { 27 | if (n === 0) return 0; 28 | if (n === 1) return 1; 29 | let pp = 0; 30 | let p = 1; 31 | for(let i = 2; i <= n; i++){ 32 | let tmp = p; 33 | p = (p + pp) % 1000000007; 34 | pp = tmp % 1000000007; 35 | } 36 | return p; // 题目规定,答案取模 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /剑指offer/15-easy-二进制中1的个数.js: -------------------------------------------------------------------------------- 1 | 2 | // 15 easy 二进制中1的个数 3 | 4 | 5 | // 请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。 6 | // 因此,如果输入 9,则该函数输出 2。 7 | // 8 | // 示例 1: 9 | // 10 | // 输入:00000000000000000000000000001011 11 | // 输出:3 12 | // 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 13 | // 示例 2: 14 | // 15 | // 输入:00000000000000000000000010000000 16 | // 输出:1 17 | // 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 18 | // 示例 3: 19 | // 20 | // 输入:11111111111111111111111111111101 21 | // 输出:31 22 | // 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 23 | // 24 | 25 | /** 26 | * @param {number} n - a positive integer 27 | * @return {number} 28 | */ 29 | var hammingWeight = function(n) { 30 | let bin = n.toString(2) 31 | let count = 0 32 | for(let i = 0; i < bin.length; i++){ 33 | if (bin[i] === '1') count++ 34 | } 35 | return count 36 | }; -------------------------------------------------------------------------------- /剑指offer/17-easy-打印从1到最大的n位数.js: -------------------------------------------------------------------------------- 1 | 2 | // 17 easy 打印从1到最大的n位数 3 | 4 | // 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。 5 | // 6 | // 示例 1: 7 | // 8 | // 输入: n = 1 9 | // 输出: [1,2,3,4,5,6,7,8,9] 10 | //   11 | // 12 | // 说明: 13 | // 14 | // 用返回一个整数列表来代替打印 15 | // n 为正整数 16 | 17 | /** 18 | * @param {number} n 19 | * @return {number[]} 20 | */ 21 | var printNumbers = function(n) { 22 | let result = []; 23 | let max = Math.pow(10, n) - 1; 24 | for(let i = 1; i <= max; i++){ 25 | result.push(i) 26 | } 27 | return result; 28 | }; -------------------------------------------------------------------------------- /剑指offer/22-easy-链表中倒数第k个节点.js: -------------------------------------------------------------------------------- 1 | 2 | // 22 easy 链表中倒数第k个节点 3 | 4 | // 输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数, 5 | // 即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点, 6 | // 从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。 7 | // 8 | //   9 | // 示例: 10 | // 给定一个链表: 1->2->3->4->5, 和 k = 2. 11 | // 返回链表 4->5. 12 | // 13 | /** 14 | * Definition for singly-linked list. 15 | * function ListNode(val) { 16 | * this.val = val; 17 | * this.next = null; 18 | * } 19 | */ 20 | /** 21 | * @param {ListNode} head 22 | * @param {number} k 23 | * @return {ListNode} 24 | */ 25 | var getKthFromEnd = function(head, k) { 26 | // 双指针解法。两个指针保持K-1个节点的差距。当快指针到终点时,慢指针就在倒数第K个节点处 27 | let i = 0; 28 | let fast = head; 29 | let resultNode = head; 30 | while(i !== k - 1){ 31 | fast = fast.next; 32 | i++; 33 | } 34 | while(fast.next){ 35 | fast = fast.next; 36 | resultNode = resultNode.next; 37 | } 38 | return resultNode; 39 | }; -------------------------------------------------------------------------------- /剑指offer/27-easy-二叉树的镜像.js: -------------------------------------------------------------------------------- 1 | // 27 easy 二叉树的镜像 2 | 3 | // 请完成一个函数,输入一个二叉树,该函数输出它的镜像。 4 | // 5 | // 例如输入: 6 | // 7 | //      4 8 | //    /   \ 9 | //   2     7 10 | //  / \   / \ 11 | // 1   3 6   9 12 | // 镜像输出: 13 | // 14 | //      4 15 | //    /   \ 16 | //   7     2 17 | //  / \   / \ 18 | // 9   6 3   1 19 | // 20 | //   21 | // 22 | // 示例 1: 23 | // 输入:root = [4,2,7,1,3,6,9] 24 | // 输出:[4,7,2,9,6,3,1] 25 | // 26 | // 限制: 27 | // 0 <= 节点个数 <= 1000 28 | 29 | // 27 二叉树的镜像 30 | var mirrorTree = function(root) { 31 | if (!root) return root; 32 | let nRoot = new TreeNode(root.val); 33 | let dfs = (curNode, nNode) => { 34 | if (curNode.left){ 35 | nNode.right = new TreeNode(curNode.left.val); 36 | dfs(curNode.left, nNode.right); 37 | } 38 | if (curNode.right){ 39 | nNode.left = new TreeNode(curNode.right.val); 40 | dfs(curNode.right, nNode.left); 41 | } 42 | }; 43 | dfs(root, nRoot); 44 | return nRoot; 45 | }; -------------------------------------------------------------------------------- /剑指offer/32-medium-从上到下打印二叉树.js: -------------------------------------------------------------------------------- 1 | // 32 medium 从上到下打印二叉树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 | // [3,9,20,15,7] 16 | //   17 | // 18 | // 提示: 19 | // 20 | // 节点总数 <= 1000 21 | // 22 | 23 | 24 | // 面试题32 - 从上到下打印二叉树 25 | var levelOrder = function(root) { 26 | if (!root) return [] 27 | // 用队列的形式层序遍历 28 | let result = []; 29 | let nodes = [root]; 30 | while(nodes.length !== 0){ 31 | if (nodes[0].left){ 32 | nodes.push(nodes[0].left); 33 | } 34 | if (nodes[0].right){ 35 | nodes.push(nodes[0].right); 36 | } 37 | result.push(nodes[0].val); 38 | nodes.shift(); 39 | } 40 | return result; 41 | }; -------------------------------------------------------------------------------- /剑指offer/38-medium-字符串的排列.js: -------------------------------------------------------------------------------- 1 | // 38 medium 字符串的排列 2 | 3 | // 输入一个字符串,打印出该字符串中字符的所有排列。 4 | // 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。 5 | // 6 | // 示例: 7 | // 输入:s = "abc" 8 | // 输出:["abc","acb","bac","bca","cab","cba"] 9 | // 10 | // 限制: 11 | // 1 <= s 的长度 <= 8 12 | 13 | let permutation = (s) => { 14 | let vis = []; 15 | let res = []; 16 | let dfs = (step, curP) => { 17 | if (step === s.length){ 18 | if(res.indexOf(curP)===-1){ 19 | res.push(curP); 20 | } 21 | return; 22 | } 23 | for (let i = 0; i < s.length; i++){ 24 | if (vis[i] === true) continue; 25 | vis[i] = true; 26 | dfs(step + 1, curP + s[i]); 27 | vis[i] = false; 28 | } 29 | } 30 | dfs(0, ''); 31 | return res; 32 | } 33 | console.log(permutation('abc')) -------------------------------------------------------------------------------- /剑指offer/53-easy-II. 0~n-1中缺失的数字.js: -------------------------------------------------------------------------------- 1 | // 53- 2 easy 0~n-1中缺失的数字 2 | 3 | // 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。 4 | // 在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。 5 | // 6 | // 示例 1: 7 | // 输入: [0,1,3] 8 | // 输出: 2 9 | // 示例 2: 10 | // 输入: [0,1,2,3,4,5,6,7,9] 11 | // 输出: 8 12 | // 13 | // 限制: 14 | // 1 <= 数组长度 <= 10000 15 | 16 | // 53 17 | var missingNumber = function(nums) { 18 | let len = nums.length; 19 | // 理论上的和。数组一共len个数,加上漏的数,一共(len + 1)个数. 数范围 0 到 len 20 | let s = (0 + len) * (len + 1) / 2; 21 | // 实际的和 22 | let sum = nums.reduce((p, n) => { 23 | return p + n; 24 | }, 0); 25 | return s - sum; 26 | }; 27 | -------------------------------------------------------------------------------- /剑指offer/53-easy-在排序数组中查找数字.js: -------------------------------------------------------------------------------- 1 | // 面试题53 - I. 在排序数组中查找数字 I easy 2 | 3 | 4 | // 统计一个数字在排序数组中出现的次数。 5 | // 6 | // 示例 1: 7 | // 输入: nums = [5,7,7,8,8,10], target = 8 8 | // 输出: 2 9 | // 示例 2: 10 | // 输入: nums = [5,7,7,8,8,10], target = 6 11 | // 输出: 0 12 | //   13 | // 14 | // 限制: 15 | // 0 <= 数组长度 <= 50000 16 | // 17 | 18 | /** 19 | * @param {number[]} nums 20 | * @param {number} target 21 | * @return {number} 22 | */ 23 | var search = function(nums, target) { 24 | if (nums.indexOf(target) === -1) return 0; 25 | return nums.lastIndexOf(target)- nums.indexOf(target) + 1; 26 | }; -------------------------------------------------------------------------------- /剑指offer/54-easy- 二叉搜索树的第k大节点.js: -------------------------------------------------------------------------------- 1 | // 54 easy 二叉搜索树的第K大节点 2 | 3 | // 给定一棵二叉搜索树,请找出其中第k大的节点。 4 | // 5 | // 示例 1: 6 | // 输入: root = [3,1,4,null,2], k = 1 7 | // 3 8 | // / \ 9 | // 1 4 10 | // \ 11 | //   2 12 | // 输出: 4 13 | // 示例 2: 14 | // 输入: root = [5,3,6,2,4,null,null,1], k = 3 15 | // 5 16 | // / \ 17 | // 3 6 18 | // / \ 19 | // 2 4 20 | // / 21 | // 1 22 | // 输出: 4 23 | //   24 | // 25 | // 限制: 26 | // 1 ≤ k ≤ 二叉搜索树元素个数 27 | 28 | // 54 二叉搜索树的第k大节点 29 | var kthLargest = function(root, k) { 30 | // BST的中序遍历是递增数组 31 | let arr = []; 32 | let dfs = (curNode) => { 33 | if (curNode.left){ 34 | dfs(curNode.left) 35 | } 36 | arr.push(curNode.val); 37 | if (curNode.right){ 38 | dfs(curNode.right); 39 | } 40 | }; 41 | dfs(root); 42 | return arr.reverse()[k - 1]; 43 | }; 44 | 45 | -------------------------------------------------------------------------------- /剑指offer/55-easy-二叉树的深度.js: -------------------------------------------------------------------------------- 1 | 2 | // 55 easy 二叉树的深度 3 | 4 | // 输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。 5 | // 6 | // 例如: 7 | // 8 | // 给定二叉树 [3,9,20,null,null,15,7], 9 | // 10 | // 3 11 | // / \ 12 | // 9 20 13 | // / \ 14 | // 15 7 15 | // 返回它的最大深度 3 。 16 | // 17 | //   18 | // 19 | // 提示: 20 | // 21 | // 节点总数 <= 10000 22 | 23 | 24 | // 55 25 | /** 26 | * @param {TreeNode} root 27 | * @return {number} 28 | */ 29 | var maxDepth = function(root) { 30 | // 先序遍历 31 | if (!root) return 0; 32 | let depth = 1; 33 | let dfs = (curNode, curDepth) => { 34 | if (curDepth > depth) depth = curDepth; 35 | if (curNode.left){ 36 | dfs(curNode.left, curDepth + 1); 37 | } 38 | if (curNode.right){ 39 | dfs(curNode.right, curDepth + 1); 40 | } 41 | }; 42 | dfs(root, 1); 43 | return depth; 44 | }; 45 | -------------------------------------------------------------------------------- /剑指offer/56-1-medium-数组中数字出现的次数.js: -------------------------------------------------------------------------------- 1 | // 数组中数字出现的次数 56 medium 2 | 3 | // 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。 4 | // 请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。 5 | // 6 | // 示例 1: 7 | // 输入:nums = [4,1,4,6] 8 | // 输出:[1,6] 或 [6,1] 9 | // 示例 2: 10 | // 输入:nums = [1,2,10,4,1,4,3,3] 11 | // 输出:[2,10] 或 [10,2] 12 | //   13 | // 14 | // 限制: 15 | // 2 <= nums <= 10000 16 | 17 | /** 18 | * @param {number[]} nums 19 | * @return {number[]} 20 | */ 21 | var singleNumbers = function(nums) { 22 | let hash = {}; 23 | for(let i = 0; i < nums.length; i++){ 24 | hash[nums[i]] = ~~(hash[nums[i]]) + 1; 25 | } 26 | let result = [] 27 | for(let k in hash){ 28 | if(hash[k] === 1){ 29 | result.push(k) 30 | } 31 | } 32 | return result; 33 | }; -------------------------------------------------------------------------------- /剑指offer/56-medium-数组中数字出现的次数2.js: -------------------------------------------------------------------------------- 1 | // 56 medium 面试题56 - II. 数组中数字出现的次数 II 2 | 3 | // 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。 4 | // 5 | // 示例 1: 6 | // 输入:nums = [3,4,3,3] 7 | // 输出:4 8 | // 示例 2: 9 | // 输入:nums = [9,1,7,9,7,9,7] 10 | // 输出:1 11 | // 12 | // 限制: 13 | // 1 <= nums.length <= 10000 14 | // 1 <= nums[i] < 2^31 15 | 16 | /** 17 | * @param {number[]} nums 18 | * @return {number} 19 | */ 20 | var singleNumber = function(nums) { 21 | let hash = {}; 22 | for(let i = 0; i < nums.length; i++){ 23 | hash[nums[i]] = ~~(hash[nums[i]]) + 1; 24 | } 25 | for(let k in hash){ 26 | if(hash[k] === 1){ 27 | return k; 28 | } 29 | } 30 | }; 31 | 32 | console.log(singleNumber([3,3,4,3])) -------------------------------------------------------------------------------- /剑指offer/57-easy-和为s的两个数字.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {number[]} nums 5 | * @param {number} target 6 | * @return {number[]} 7 | */ 8 | var twoSum = function(nums, target) { 9 | 10 | }; -------------------------------------------------------------------------------- /剑指offer/58-easy-左旋转字符串.js: -------------------------------------------------------------------------------- 1 | // 58 easy 左旋转字符串 2 | 3 | // 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。 4 | // 请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。 5 | // 6 | // 7 | // 示例 1: 8 | // 输入: s = "abcdefg", k = 2 9 | // 输出: "cdefgab" 10 | // 示例 2: 11 | // 输入: s = "lrloseumgh", k = 6 12 | // 输出: "umghlrlose" 13 | //   14 | // 15 | // 限制: 16 | // 1 <= k < s.length <= 10000 17 | // 18 | 19 | 20 | /** 21 | * @param {string} s 22 | * @param {number} n 23 | * @return {string} 24 | */ 25 | var reverseLeftWords = function(s, n) { 26 | let left = s.slice(n); 27 | let right = s.slice(0, n); 28 | return left + right; 29 | }; -------------------------------------------------------------------------------- /剑指offer/58-easy-翻转单词顺序1.js: -------------------------------------------------------------------------------- 1 | // 58 easy 翻转单词顺序1 2 | 3 | // 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。 4 | // 为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。 5 | // 6 | // 示例 1: 7 | // 输入: "the sky is blue" 8 | // 输出: "blue is sky the" 9 | // 示例 2: 10 | // 输入: "  hello world!  " 11 | // 输出: "world! hello" 12 | // 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 13 | // 示例 3: 14 | // 输入: "a good   example" 15 | // 输出: "example good a" 16 | // 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 17 | // 18 | // 说明: 19 | // 无空格字符构成一个单词。 20 | // 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 21 | // 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 22 | 23 | 24 | /** 25 | * @param {string} s 26 | * @return {string} 27 | */ 28 | var reverseWords = function(s) { 29 | s = s.trim(); 30 | s = s.replace(/\s{2,}/g, ' '); 31 | let arr = s.split(' '); 32 | return arr.reverse().join(' '); 33 | }; -------------------------------------------------------------------------------- /剑指offer/59 - I-easy-滑动窗口的最大值.js: -------------------------------------------------------------------------------- 1 | //面试题59 - I. 滑动窗口的最大值 2 | 3 | //给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。 4 | // 5 | // 示例: 6 | // 7 | // 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 8 | // 输出: [3,3,5,5,6,7] 9 | // 解释: 10 | // 11 | // 滑动窗口的位置 最大值 12 | // --------------- ----- 13 | // [1 3 -1] -3 5 3 6 7 3 14 | // 1 [3 -1 -3] 5 3 6 7 3 15 | // 1 3 [-1 -3 5] 3 6 7 5 16 | // 1 3 -1 [-3 5 3] 6 7 5 17 | // 1 3 -1 -3 [5 3 6] 7 6 18 | // 1 3 -1 -3 5 [3 6 7] 7 19 | //   20 | // 21 | // 提示: 22 | // 你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。 23 | // 24 | var maxSlidingWindow = function(nums, k) { 25 | if (!nums.length) return []; 26 | let i = 0; 27 | let result = []; 28 | let curMax; 29 | while(i <= nums.length - k){ 30 | // 更新最大值 31 | curMax = Math.max(...nums.slice(i, i + k)); 32 | result.push(curMax); 33 | i++; 34 | } 35 | return result; 36 | }; -------------------------------------------------------------------------------- /剑指offer/61-easy-扑克牌中的顺子.js: -------------------------------------------------------------------------------- 1 | // 61 easy 扑克牌中的顺子 2 | 3 | // 从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。 4 | // 2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。 5 | //   6 | // 7 | // 示例 1: 8 | // 输入: [1,2,3,4,5] 9 | // 输出: True 10 | //   11 | // 12 | // 示例 2: 13 | // 输入: [0,0,1,2,5] 14 | // 输出: True 15 | // 16 | // 限制: 17 | // 数组长度为 5  18 | // 数组的数取值为 [0, 13] . 19 | 20 | 21 | let isStraight = (nums) => { 22 | nums.sort((a, b) => { 23 | return a - b; 24 | }) 25 | let zeroN = nums.lastIndexOf(0) + 1; 26 | let restArr = nums.slice(nums.lastIndexOf(0) + 1); 27 | let c = 0 28 | for (let i = 0; i < restArr.length - 1; i++){ 29 | if (restArr[i+1] - restArr[i] > 1){ 30 | c += restArr[i+1] - restArr[i] - 1 31 | }else if(restArr[i+1] === restArr[i]){ // 只要有相等的元素,肯定不是顺子 32 | return false; 33 | } 34 | } 35 | return c <= zeroN; 36 | } 37 | console.log(isStraight([1,2,3,4,5])); -------------------------------------------------------------------------------- /剑指offer/63-medium-股票的最大利润.js: -------------------------------------------------------------------------------- 1 | // 63 medium 股票的最大利润 2 | // 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少? 3 | 4 | // 示例 1: 5 | // 输入: [7,1,5,3,6,4] 6 | // 输出: 5 7 | // 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 8 | // 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 9 | 10 | // 示例 2: 11 | // 输入: [7,6,4,3,1] 12 | // 输出: 0 13 | // 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 14 | 15 | // 限制: 16 | // 0 <= 数组长度 <= 10^5 17 | 18 | /** 19 | * @param {number[]} prices 20 | * @return {number} 21 | */ 22 | var maxProfit = function(prices) { 23 | if(!prices.length || prices.length === 1) return 0; 24 | let max = 0 25 | for(let i = 0;i < prices.length;i++){ 26 | for(let j = i + 1;j< prices.length;j++){ 27 | if(prices[i] < prices[j]){ 28 | max = Math.max(max, prices[j] - prices[i]) 29 | } 30 | } 31 | } 32 | return max; 33 | }; -------------------------------------------------------------------------------- /剑指offer/66-easy-构建乘积数组.js: -------------------------------------------------------------------------------- 1 | // 面试题66. 构建乘积数组 easy 2 | 3 | // 给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1], 4 | // 其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。 5 | // 6 | // 示例: 7 | // 输入: [1,2,3,4,5] 8 | // 输出: [120,60,40,30,24] 9 | // 10 | // 提示: 11 | // 所有元素乘积之和不会溢出 32 位整数 12 | // a.length <= 100000 13 | 14 | 15 | var constructArr = function(a) { 16 | if (!a.length) return []; 17 | // 前缀积 18 | let p = [a[0]] 19 | for(let i = 1; i < a.length; i++){ 20 | p[i] = p[i-1] * a[i]; 21 | } 22 | // 后缀积 23 | let n = []; 24 | n[a.length - 1] = a[a.length - 1]; 25 | for (let i = a.length - 2; i >= 0; i--) { 26 | n[i] = n[i + 1] * a[i]; 27 | } 28 | 29 | // 结果 30 | let result = [n[1]] // 第一个数 31 | for(let i = 1; i <= a.length - 2; i++){ 32 | result.push(p[i - 1] * n[i + 1]); 33 | } 34 | result.push(p[a.length - 2]) // 最后数 35 | return result; 36 | }; -------------------------------------------------------------------------------- /动态规划.md: -------------------------------------------------------------------------------- 1 | ## 动态规划 2 | 3 | * 53 easy 最大子序和 4 | * 62 medium 不同路径 5 | * 64 medium 最小路径和 6 | * 70 easy 爬楼梯 7 | * 152 medium 乘积最大子序列 8 | * 198 easy 打家劫舍 9 | * 213 medium 打家劫舍II 10 | * 221 medium 最大正方形 11 | * 249 medium 完全平方数 12 | * 300 medium 最长上升子序列 13 | * 322 medium 零钱兑换 14 | * 375 medium 猜数字大小2 15 | * 416 medium 分割等和子集 16 | * 583 medium 两个字符串的删除操作 17 | * 746 easy 使用最小花费爬楼梯 18 | * 931 medium 下降路径最小和 19 | * 1143 medium 最长公共子序列 20 | * 1277 medium 统计全为 1 的正方形子矩阵 21 | * 5363 hard 做菜顺序 22 | * 5383 hard 给 N x 3 网格图涂色的方案数 -------------------------------------------------------------------------------- /动态规划/152-medium-乘积最大子序列.js: -------------------------------------------------------------------------------- 1 | // 152 medium 乘积最大子序列 2 | 3 | // 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。 4 | // 5 | // 示例 1: 6 | // 输入: [2,3,-2,4] 7 | // 输出: 6 8 | // 解释: 子数组 [2,3] 有最大乘积 6。 9 | // 示例 2: 10 | // 输入: [-2,0,-1] 11 | // 输出: 0 12 | // 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 13 | 14 | 15 | /** 16 | * @param {number[]} nums 17 | * @return {number} 18 | */ 19 | var maxProduct = function(nums) { 20 | if(!nums.length)return 0; 21 | 22 | let dp = [nums[0]]; 23 | let curMax = nums[0]; 24 | let curMin = nums[0]; 25 | for(let i = 1; i < nums.length; i++){ 26 | let tmp = curMax; 27 | curMax = Math.max(Math.max(nums[i] * curMax, nums[i] * curMin), nums[i]); 28 | curMin = Math.min(Math.min(nums[i] * tmp, nums[i] * curMin), nums[i]); 29 | dp[i] = Math.max(curMax, dp[i-1]); 30 | } 31 | return dp[dp.length - 1] 32 | }; 33 | // console.log(maxProduct([2,3,-2,4])) 34 | console.log(maxProduct([-2,3,-4])) -------------------------------------------------------------------------------- /动态规划/279-medium-完全平方数.js: -------------------------------------------------------------------------------- 1 | // 279 medium 完全平方数 2 | 3 | //给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 4 | // 5 | // 示例 1: 6 | // 输入: n = 12 7 | // 输出: 3 8 | // 解释: 12 = 4 + 4 + 4. 9 | // 示例 2: 10 | // 输入: n = 13 11 | // 输出: 2 12 | // 解释: 13 = 4 + 9. 13 | // 14 | 15 | /** 16 | * @param {number} n 17 | * @return {number} 18 | */ 19 | var numSquares = function(n) { 20 | // 模拟数组 21 | let arr = [] 22 | for(let i = 0; i <= n; i++){ 23 | arr.push(0); 24 | } 25 | 26 | let dp = [0] 27 | 28 | for(let i = 1; i < arr.length; i++){ 29 | // 初始化为需要 i个1 那么多的完全平方数 30 | dp[i] = i; 31 | for(let j = 1; i - j * j >= 0; j++){ 32 | dp[i] = Math.min(dp[i], dp[i - j*j] + 1); 33 | } 34 | } 35 | return dp[n]; 36 | }; 37 | 38 | console.log(numSquares(12)); -------------------------------------------------------------------------------- /动态规划/300-medium-最长上升子序列.js: -------------------------------------------------------------------------------- 1 | // 300 medium 最长上升子序列 2 | 3 | // 给定一个无序的整数数组,找到其中最长上升子序列的长度。 4 | // 5 | // 示例: 6 | // 输入: [10,9,2,5,3,7,101,18] 7 | // 输出: 4 8 | // 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 9 | // 说明: 10 | // 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。 11 | // 你算法的时间复杂度应该为 O(n2) 。 12 | // 进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗? 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number} 17 | */ 18 | var lengthOfLIS = function(nums) { 19 | if(!nums.length) return 0; 20 | if(!nums.length === 1)return 1; 21 | 22 | // 初始化为1,默认都是单个独立上升子序列 23 | let dp = [] 24 | for(let i = 0; i < nums.length; i++){ 25 | dp[i] = 1; 26 | } 27 | for(let i = 0; i < nums.length; i++){ 28 | for(let j = 0; j < i; j++){ 29 | if(nums[i] > nums[j]){ 30 | dp[i] = Math.max(dp[i], dp[j] + 1); 31 | } 32 | } 33 | } 34 | return Math.max(...dp); 35 | }; 36 | 37 | console.log(lengthOfLIS([10,9,2,5,3,7,101,18])) -------------------------------------------------------------------------------- /动态规划/322-medium-零钱兑换.js: -------------------------------------------------------------------------------- 1 | // 322 medium 2 | 3 | // 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。 4 | // 如果没有任何一种硬币组合能组成总金额,返回 -1。 5 | // 6 | // 示例 1: 7 | // 输入: coins = [1, 2, 5], amount = 11 8 | // 输出: 3 9 | // 解释: 11 = 5 + 5 + 1 10 | // 示例 2: 11 | // 输入: coins = [2], amount = 3 12 | // 输出: -1 13 | // 说明: 14 | // 你可以认为每种硬币的数量是无限的。 15 | 16 | 17 | /** 18 | * @param {number[]} coins 19 | * @param {number} amount 20 | * @return {number} 21 | */ 22 | var coinChange = function(coins, amount) { 23 | let dp = new Array(amount + 1).fill(amount + 1); 24 | 25 | dp[0] = 0; 26 | for(let money = 1; money <= amount; money++){ 27 | 28 | for(let j = 0; j < coins.length; j++){ 29 | if(coins[j] <= money){ 30 | dp[money] = Math.min(dp[money], dp[money - coins[j]] + 1) 31 | } 32 | } 33 | } 34 | return dp[amount] > amount ? -1 : dp[amount] 35 | }; 36 | 37 | console.log(coinChange([1, 2, 5], 11)) -------------------------------------------------------------------------------- /动态规划/63-medium-不同路径2.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * @param {number[][]} obstacleGrid 6 | * @return {number} 7 | */ 8 | var uniquePathsWithObstacles = function(obstacleGrid) { 9 | 10 | }; -------------------------------------------------------------------------------- /动态规划/70-easy-爬楼梯.js: -------------------------------------------------------------------------------- 1 | // easy 70 爬楼梯 2 | // 3 | // 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 4 | // 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 5 | // 注意:给定 n 是一个正整数。 6 | // 7 | // 示例 1: 8 | // 输入: 2 9 | // 输出: 2 10 | // 解释: 有两种方法可以爬到楼顶。 11 | // 1. 1 阶 + 1 阶 12 | // 2. 2 阶 13 | 14 | // 示例 2: 15 | // 输入: 3 16 | // 输出: 3 17 | // 解释: 有三种方法可以爬到楼顶。 18 | // 1. 1 阶 + 1 阶 + 1 阶 19 | // 2. 1 阶 + 2 阶 20 | // 3. 2 阶 + 1 阶 21 | 22 | 23 | 24 | /** 25 | * @param {number} n 26 | * @return {number} 27 | */ 28 | var climbStairs = function(n) { 29 | if(n===3 || n===2 || n=== 1) return n; 30 | let arr = [0,1,2,3] 31 | for(let i = 4; i <= n; i++){ 32 | arr.push(arr[i-1] + arr[i-2]) 33 | } 34 | return arr[n] 35 | }; 36 | 37 | console.log(climbStairs(4)) -------------------------------------------------------------------------------- /动态规划/746-easy-使用最小花费爬楼梯.js: -------------------------------------------------------------------------------- 1 | // 746 easy 使用最小花费爬楼梯 2 | 3 | // 数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始)。 4 | // 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。 5 | // 您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。 6 | // 7 | // 示例 1: 8 | // 输入: cost = [10, 15, 20] 9 | // 输出: 15 10 | // 解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。 11 | 12 | //  示例 2: 13 | // 输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 14 | // 输出: 6 15 | // 解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。 16 | // 注意: 17 | // cost 的长度将会在 [2, 1000]。 18 | // 每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。 19 | 20 | /** 21 | * @param {number[]} cost 22 | * @return {number} 23 | */ 24 | var minCostClimbingStairs = function(cost) { 25 | cost.push(0) 26 | let arr = [cost[0], cost[1]] 27 | for(let i = 2; i < cost.length; i++){ 28 | arr[i] = cost[i] + Math.min(arr[i-1], arr[i-2]) 29 | } 30 | return arr[cost.length - 1] 31 | }; 32 | 33 | console.log(minCostClimbingStairs([0,1,1,0])) -------------------------------------------------------------------------------- /博弈/取球游戏.js: -------------------------------------------------------------------------------- 1 | 2 | // 巴什博弈(Bash Game) 3 | 4 | 5 | // 一堆球,共100个。两个人轮流拿,拿到最后一个赢。 6 | // 最少拿1个,最多拿9个。 7 | // 如果你后拿,制胜策略是什么? 8 | 9 | // 答:10个一组,共10组。 10 | // 如果对方拿1,你就拿9;对方拿2,你就拿8。总之,一轮中,你拿的和对方拿的 sum = 10; 11 | // 最后会剩下10个球,无论对方拿几个,你一次性拿走最后的几个,即可。 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /双指针.md: -------------------------------------------------------------------------------- 1 | ## 双指针 2 | 3 | * 11 medium 盛最多水的容器 4 | * 287 medium 寻找重复数 5 | * 345 翻转字符串中的元音字母 6 | * 349 两个数组的交集 7 | * 350 两个数组的交集2 8 | * 674 easy 最长连续递增序列 9 | * 881 medium 救生艇 10 | * 925 长按键入 11 | * 986 medium 区间列表的交集 12 | * 1004 medium 最大连续1的个数3 -------------------------------------------------------------------------------- /双指针/11-medium-盛最多水的容器.js: -------------------------------------------------------------------------------- 1 | // 11 medium 盛最多水的容器 2 | 3 | // 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。 4 | // 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。 5 | // 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 6 | // 说明:你不能倾斜容器,且 n 的值至少为 2。 7 | 8 | // 示例: 9 | // 输入: [1,8,6,2,5,4,8,3,7] 10 | // 输出: 49 11 | 12 | 13 | /** 14 | * @param {number[]} height 15 | * @return {number} 16 | */ 17 | var maxArea = function(height) { 18 | if(!height.length) return 0; 19 | 20 | // 双指针解法。 21 | let l = 0; 22 | let r = height.length - 1; 23 | let area = 0; 24 | while(l < r){ 25 | let cur = Math.min(height[r], height[l]) * (r - l); 26 | area = Math.max(cur, area); 27 | 28 | // 移动指针 29 | // 如果面积想要更大,就把较矮一侧,往里移动 30 | if (height[l] < height[r]){ 31 | l++; 32 | } else { 33 | r--; 34 | } 35 | } 36 | return area; 37 | }; -------------------------------------------------------------------------------- /双指针/287-lookforRepeatNumber.js: -------------------------------------------------------------------------------- 1 | // 287 medium 寻找重复数 2 | 3 | // 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n), 4 | // 可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 5 | // 6 | // 示例 1: 7 | // 输入: [1,3,4,2,2] 8 | // 输出: 2 9 | 10 | // 示例 2: 11 | // 输入: [3,1,3,4,2] 12 | // 输出: 3 13 | 14 | // 说明: 15 | // 不能更改原数组(假设数组是只读的)。 16 | // 只能使用额外的 O(1) 的空间。 17 | // 时间复杂度小于 O(n2) 。 18 | // 数组中只有一个重复的数字,但它可能不止重复出现一次。 19 | 20 | 21 | /** 22 | * @param {number[]} nums 23 | * @return {number} 24 | */ 25 | var findDuplicate = function(nums) { 26 | 27 | }; 28 | 29 | console.log(findDuplicate([3,1,3,4,2])) -------------------------------------------------------------------------------- /双指针/350-easy-两个数组交集2.js: -------------------------------------------------------------------------------- 1 | // 给定两个数组,编写一个函数来计算它们的交集。 2 | // 3 | // 示例 1: 4 | // 输入: nums1 = [1,2,2,1], nums2 = [2,2] 5 | // 输出: [2,2] 6 | 7 | // 示例 2: 8 | // 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 9 | // 输出: [4,9] 10 | 11 | // 说明: 12 | // 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 13 | // 我们可以不考虑输出结果的顺序。 14 | 15 | 16 | /** 17 | * @param {number[]} nums1 18 | * @param {number[]} nums2 19 | * @return {number[]} 20 | */ 21 | var intersect = function(nums1, nums2) { 22 | 23 | nums1.sort((a, b) => { 24 | return a-b 25 | }) 26 | nums2.sort((a, b) => { 27 | return a-b 28 | }) 29 | let newArr = [] 30 | let i = 0, j = 0 31 | while(i !== nums1.length && j !== nums2.length){ 32 | if(nums2[j] === nums1[i]){ 33 | newArr.push(nums1[i]) 34 | i++;j++; 35 | } else 36 | // 可以继续往下 37 | if (nums2[j] < nums1[i]){ 38 | j++; 39 | }else if (nums2[j] > nums1[i]){ 40 | i++; 41 | } 42 | } 43 | return newArr 44 | }; -------------------------------------------------------------------------------- /周六/1009-easy-十进制整数的反码.js: -------------------------------------------------------------------------------- 1 | // 1009 easy 十进制整数的反码 2 | 3 | // 每个非负整数 N 都有其二进制表示。例如, 5 可以被表示为二进制 "101",11 可以用二进制 "1011" 表示,依此类推。注意,除 N = 0 外,任何二进制表示中都不含前导零。 4 | // 二进制的反码表示是将每个 1 改为 0 且每个 0 变为 1。例如,二进制数 "101" 的二进制反码为 "010"。 5 | // 给定十进制数 N,返回其二进制表示的反码所对应的十进制整数。 6 | // 7 | // 8 | // 示例 1: 9 | // 输入:5 10 | // 输出:2 11 | // 解释:5 的二进制表示为 "101",其二进制反码为 "010",也就是十进制中的 2 。 12 | 13 | // 示例 2: 14 | // 输入:7 15 | // 输出:0 16 | // 解释:7 的二进制表示为 "111",其二进制反码为 "000",也就是十进制中的 0 。 17 | 18 | // 示例 3: 19 | // 输入:10 20 | // 输出:5 21 | // 解释:10 的二进制表示为 "1010",其二进制反码为 "0101",也就是十进制中的 5 。 22 | //   23 | // 提示: 24 | // 0 <= N < 10^9 25 | 26 | 27 | 28 | /** 29 | * @param {number} N 30 | * @return {number} 31 | */ 32 | var bitwiseComplement = function(N) { 33 | let bin = N.toString(2); 34 | let s = '' 35 | for(let i = 0; i < bin.length; i++){ 36 | s += bin[i] === '1'? '0':'1' 37 | } 38 | return parseInt(s, 2) 39 | }; 40 | 41 | console.log(bitwiseComplement(5)) 42 | console.log(bitwiseComplement(7)) 43 | console.log(bitwiseComplement(10)) -------------------------------------------------------------------------------- /周六/215-medium-数组中的第K个最大元素.js: -------------------------------------------------------------------------------- 1 | // 215 medium 数组中第K个最大元素 2 | 3 | // 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 4 | // 5 | // 示例 1: 6 | // 输入: [3,2,1,5,6,4] 和 k = 2 7 | // 输出: 5 8 | 9 | // 示例 2: 10 | // 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 11 | // 输出: 4 12 | 13 | // 说明: 14 | // 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 15 | 16 | 17 | /** 18 | * 排序 19 | * @param {number[]} nums 20 | * @param {number} k 21 | * @return {number} 22 | */ 23 | var findKthLargest = function(nums, k) { 24 | nums.sort((a,b) => { 25 | return b-a 26 | }) 27 | return nums[k-1] 28 | }; 29 | 30 | console.log(findKthLargest([3,2,3,1,2,4,5,5,6], 4)) 31 | console.log(findKthLargest([3,2,1,5,6,4], 2)) -------------------------------------------------------------------------------- /周六/238-medium-除自身外数组的乘积.js: -------------------------------------------------------------------------------- 1 | // 238 medium 除自身外数组的乘积 2 | 3 | // 给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output , 4 | // 其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。 5 | // 6 | // 示例: 7 | // 输入: [1,2,3,4] 8 | // 输出: [24,12,8,6] 9 | // 说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。 10 | // 11 | // 进阶: 12 | // 你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。) 13 | 14 | 15 | /** 16 | * 题解基本都一样,左边乘积 * 右边乘积 17 | * @param {number[]} nums 18 | * @return {number[]} 19 | */ 20 | var productExceptSelf = function(nums) { 21 | let result = [] 22 | 23 | let cur = 1 24 | result[0] = 1; 25 | for(let i = 1; i < nums.length; i++){ 26 | cur *= nums[i - 1] 27 | result[i] = cur; 28 | } 29 | 30 | cur = 1; 31 | for (let i = nums.length - 2; i >= 0; i--) { 32 | cur *= nums[i + 1] 33 | result[i] *= cur 34 | } 35 | return result 36 | }; 37 | 38 | console.log(productExceptSelf([1,2,3,4])) -------------------------------------------------------------------------------- /周六/386-medium-字典序排数.js: -------------------------------------------------------------------------------- 1 | // 386 medium 字典序排数 2 | 3 | // 给定一个整数 n, 返回从 1 到 n 的字典顺序。 4 | // 5 | // 例如, 6 | // 给定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。 7 | // 8 | // 请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。 9 | 10 | 11 | /** 12 | * @param {number} n 13 | * @return {number[]} 14 | */ 15 | var lexicalOrder = function(n) { 16 | let arr =[] 17 | for(let i = 1; i <= n; i++){ 18 | arr.push(i) 19 | } 20 | arr.sort() 21 | return arr 22 | }; 23 | 24 | console.log(lexicalOrder(13)) -------------------------------------------------------------------------------- /周六/77-medium-组合.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @param {number} n 4 | * @param {number} k 5 | * @return {number[][]} 6 | */ 7 | var combine = function(n, k) { 8 | let arr = [] 9 | for(let i = 1; i <= n; i++){ 10 | arr.push(i) 11 | } 12 | 13 | let fn = (arr, count) => { 14 | if (arr.length && count === 1) return arr; 15 | count--; 16 | for(let i = 0; i < arr.length - k + 1; i++){ 17 | let subArr = fn(arr.slice(i + 1), count) 18 | subArr.forEach((item) => { 19 | resultArr.push([arr[i]].concat([item])) 20 | }) 21 | } 22 | return resultArr; 23 | } 24 | 25 | let resultArr = [] 26 | return fn(arr, k) 27 | }; 28 | 29 | console.log(combine(4, 3)) -------------------------------------------------------------------------------- /周六/876-链表的中间节点.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * Definition for singly-linked list. 5 | * function ListNode(val) { 6 | * this.val = val; 7 | * this.next = null; 8 | * } 9 | */ 10 | /** 11 | * @param {ListNode} head 12 | * @return {ListNode} 13 | */ 14 | var middleNode = function(head) { 15 | let len = 0; 16 | let node = head 17 | while(node){ 18 | len++; 19 | 20 | node = node.next; 21 | } 22 | 23 | let mid = ~~(len / 2) 24 | len = 0; 25 | node = head; 26 | while(node){ 27 | if (len === mid) return node; 28 | len++; 29 | node = node.next; 30 | } 31 | 32 | }; -------------------------------------------------------------------------------- /周六/965-easy-单值二叉树.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * function TreeNode(val) { 6 | * this.val = val; 7 | * this.left = this.right = null; 8 | * } 9 | */ 10 | /** 11 | * @param {TreeNode} root 12 | * @return {boolean} 13 | */ 14 | var isUnivalTree = function(root) { 15 | let curNode = root; 16 | let v = curNode.val 17 | let fn = (node, v) => { 18 | if (node.val !== v){ 19 | return false 20 | } else { 21 | if(node.left){ 22 | fn(node.left, v); 23 | } 24 | if(node.right){ 25 | fn(node.right, v); 26 | } 27 | } 28 | return true 29 | } 30 | return fn(curNode, v) !== false 31 | }; -------------------------------------------------------------------------------- /周赛/1.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var buildArray = function(target, n) { 4 | let res = [] 5 | let tmp = target[0]; 6 | if (tmp !== 1){ 7 | for(let i = 1; i < tmp; i++){ 8 | res.push('Push') 9 | res.push('Pop') 10 | } 11 | res.push('Push'); 12 | }else{ 13 | res.push('Push') 14 | } 15 | 16 | for(let i = 1; i < target.length; i++){ 17 | if (target[i] - target[i-1] === 1){ 18 | res.push('Push') 19 | }else{ 20 | let dif = target[i] - target[i-1]; 21 | for(let i = 1; i < dif; i++){ 22 | res.push('Push') 23 | res.push('Pop') 24 | } 25 | res.push('Push') 26 | } 27 | } 28 | return res; 29 | }; -------------------------------------------------------------------------------- /周赛/2.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var countTriplets = function(arr) { 4 | let res=0 5 | for(let i = 0; i < arr.length; i++){ 6 | for(let j = i+1; j < arr.length; j++){ 7 | for(let k = j; k < arr.length; k++){ 8 | let a=0; 9 | let b=0; 10 | for(let m = i; m <=j-1; m++){ 11 | a = a ^ arr[m]; 12 | } 13 | for(let n = j; n <=k; n++){ 14 | b = b ^ arr[n]; 15 | } 16 | if (a === b){ 17 | res++ 18 | } 19 | } 20 | } 21 | } 22 | return res; 23 | }; -------------------------------------------------------------------------------- /周赛/3.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var minTime = function(n, edges, hasApple) { 4 | let parent = {}; 5 | for(let i = 0; i < edges.length; i++){ 6 | parent[edges[i][1]] = edges[i][0]; 7 | } 8 | 9 | let cnt = 0; 10 | let vis = {}; 11 | for(let i = 0; i < hasApple.length; i++){ 12 | if (!hasApple[i])continue; 13 | if(hasApple[i] && i === 0)continue; 14 | let aa = i; 15 | while(parent[aa] !== 0){ 16 | if (!vis[parent[aa] + ',' + aa]){ 17 | vis[parent[aa] + ',' + aa] = true; 18 | cnt += 2; 19 | } 20 | aa = parent[aa]; 21 | } 22 | if (!vis[parent[aa] + ',' + aa]){ 23 | vis[parent[aa] + ',' + aa] = true; 24 | cnt += 2; 25 | } 26 | } 27 | return cnt 28 | }; 29 | 30 | // console.log(minTime(4, 31 | // [[0,1],[1,2],[0,3]], 32 | // [true,true,true,true])) -------------------------------------------------------------------------------- /周赛2/1.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var busyStudent = function(startTime, endTime, queryTime) { 4 | let res = 0 5 | for(let i = 0; i < startTime.length; i++){ 6 | if (startTime[i] <= queryTime && endTime[i] >= queryTime){ 7 | res++; 8 | } 9 | } 10 | return res 11 | }; -------------------------------------------------------------------------------- /周赛2/2.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | var arrangeWords = function(text) { 5 | let arr = text.split(' '); 6 | // arr.sort((a,b) => { 7 | // if(a.length === b.length){ 8 | // return 0 9 | // } 10 | // return a.length - b.length 11 | // }) 12 | 13 | let len = 1 14 | let cnt = 0 15 | let aaa = [] 16 | while(cnt < arr.length){ 17 | for(let i = 0; i < arr.length; i++){ 18 | if(arr[i].length === len){ 19 | aaa.push(arr[i]); 20 | cnt++ 21 | } 22 | } 23 | len++; 24 | } 25 | 26 | 27 | let f = aaa[0].split('') 28 | f[0] = f[0].toUpperCase() 29 | aaa[0] = f.join(''); 30 | 31 | 32 | let r = aaa.join(' ') 33 | let n = r[0] 34 | for(let i = 1; i < r.length; i++){ 35 | n += r[i].toLowerCase() 36 | } 37 | return n; 38 | }; 39 | 40 | console.log(arrangeWords("Jtik hrzrvhbmk gbo cfhmiqwonj ojkew ufvledv bomoeqt ops jgi zdhvbpbb zczmepdfpm jry rjazc titttcu")) -------------------------------------------------------------------------------- /周赛2/3.js: -------------------------------------------------------------------------------- 1 | 2 | let isSub = (a1, a2) => { 3 | for(let i = 0; i < a1.length; i++){ 4 | if(a2.indexOf(a1[i]) === -1){ 5 | return false 6 | } 7 | } 8 | return true 9 | } 10 | 11 | var peopleIndexes = function(favoriteCompanies) { 12 | let res = [] 13 | for(let i = 0; i < favoriteCompanies.length; i++){ 14 | for(let j = 0; j < favoriteCompanies.length; j++){ 15 | if(i!==j && isSub(favoriteCompanies[i], favoriteCompanies[j])){ 16 | if(res.indexOf(i)===-1){ 17 | res.push(i) 18 | } 19 | } 20 | } 21 | } 22 | 23 | let aa = [] 24 | for(let i = 0; i < favoriteCompanies.length; i++){ 25 | aa.push(i) 26 | } 27 | for (let i = res.length - 1; i >= 0; i--) { 28 | aa.splice(res[i], 1) 29 | } 30 | return aa 31 | }; 32 | 33 | console.log(peopleIndexes([["leetcode","google","facebook"],["google","microsoft"],["google","facebook"],["google"],["amazon"]])) -------------------------------------------------------------------------------- /周赛2/5.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/周赛2/5.js -------------------------------------------------------------------------------- /周赛3/1.js: -------------------------------------------------------------------------------- 1 | 2 | var maxDepth = function(s) { 3 | let stack = []; 4 | let max = 0; 5 | for(let i = 0; i < s.length; i++){ 6 | if (s[i] === ')'){ 7 | stack.pop(); 8 | } else if(s[i] === '('){ 9 | stack.push(s[i]); 10 | }else{ 11 | max = Math.max(max, stack.length); 12 | } 13 | } 14 | return max; 15 | }; -------------------------------------------------------------------------------- /周赛3/2.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @param {number} n 4 | * @param {number[][]} roads 5 | * @return {number} 6 | */ 7 | var maximalNetworkRank = function(n, roads) { 8 | let h = {} 9 | for(let i = 0; i <= n-1; i++){ 10 | h[i] = [] 11 | } 12 | for(let i = 0; i < roads.length; i++){ 13 | h[roads[i][0]].push(roads[i][1]) 14 | h[roads[i][1]].push(roads[i][0]) 15 | } 16 | let m = 0; 17 | for(let i = 0; i < n; i++){ 18 | for(let j = i + 1; j < n; j++){ 19 | let r = h[i].length + h[j].length; 20 | if(h[i].indexOf(j) !== -1 || h[j].indexOf(i) !== -1){ 21 | r--; 22 | } 23 | m = Math.max(m, r); 24 | } 25 | } 26 | return m; 27 | }; 28 | 29 | console.log('111: ', maximalNetworkRank(4, 30 | [[0,1],[0,3],[1,2],[1,3]] 31 | )) -------------------------------------------------------------------------------- /周赛3/3.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /周赛3/4.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/周赛3/4.js -------------------------------------------------------------------------------- /周赛3/5.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/周赛3/5.js -------------------------------------------------------------------------------- /周赛4/2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/周赛4/2.js -------------------------------------------------------------------------------- /周赛4/3.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /周赛4/4.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/周赛4/4.js -------------------------------------------------------------------------------- /周赛4/5.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/周赛4/5.js -------------------------------------------------------------------------------- /哈希表/1189-easy-气球的最大数量.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {string} text 5 | * @return {number} 6 | */ 7 | var maxNumberOfBalloons = function(text) { 8 | let s = 'balloon' 9 | let hash = {} 10 | for(let i = 0; i < text.length; i++){ 11 | if(s.includes(text[i])){ 12 | hash[text[i]] = (~~hash[text[i]]) + 1 13 | } 14 | } 15 | if(!hash['b'] || !hash['a'] || ~~hash['l'] < 2 || ~~hash['o'] < 2 || !hash['n']) return 0; 16 | hash['l'] = ~~(hash['l']/2) 17 | hash['o'] = ~~(hash['o']/2) 18 | return Math.min(...Object.values(hash)) 19 | }; 20 | 21 | console.log(maxNumberOfBalloons('leetcode')) -------------------------------------------------------------------------------- /哈希表/1287-easy-有序数组中出现次数超过25%的元素.js: -------------------------------------------------------------------------------- 1 | //1287. 有序数组中出现次数超过25%的元素 easy 2 | 3 | // 给你一个非递减的 有序 整数数组,已知这个数组中恰好有一个整数,它的出现次数超过数组元素总数的 25%。 4 | // 请你找到并返回这个整数 5 | // 6 | // 示例: 7 | // 输入:arr = [1,2,2,6,6,6,6,7,10] 8 | // 输出:6 9 | // 10 | // 提示: 11 | // 1 <= arr.length <= 10^4 12 | // 0 <= arr[i] <= 10^5 13 | 14 | /** 15 | * @param {number[]} arr 16 | * @return {number} 17 | */ 18 | var findSpecialInteger = function(arr) { 19 | // 思路:哈希表统计词频 20 | let hash = {} 21 | for(let i = 0; i < arr.length; i++){ 22 | hash[arr[i]] = ~~hash[arr[i]] + 1; 23 | } 24 | 25 | let len = arr.length * (1/4) 26 | for(let key in hash){ 27 | if (hash[key] > len){ 28 | return key / 1; 29 | } 30 | } 31 | }; -------------------------------------------------------------------------------- /哈希表/136-easy-只出现一次的数字.js: -------------------------------------------------------------------------------- 1 | // 136 easy 只出现一次的数字 2 | // 跟540题一样的解法 3 | 4 | // 5 | // 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 6 | // 7 | // 说明: 8 | // 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 9 | // 10 | // 示例 1: 11 | // 输入: [2,2,1] 12 | // 输出: 1 13 | 14 | // 示例 2: 15 | // 输入: [4,1,2,1,2] 16 | // 输出: 4 17 | 18 | 19 | /** 20 | * 解法1:异或 21 | * @param {number[]} nums 22 | * @return {number} 23 | */ 24 | var singleNumber = function(nums) { 25 | let result = nums[0] 26 | for(let i = 1; i < nums.length; i++){ 27 | result = result ^ nums[i] 28 | } 29 | return result 30 | }; 31 | 32 | console.log(singleNumber([4,1,2,1,2])); 33 | console.log(singleNumber([2,1,2])); 34 | -------------------------------------------------------------------------------- /哈希表/187-medium-重复的DNA序列.js: -------------------------------------------------------------------------------- 1 | // 187 medium 重复的DNA序列 2 | // 3 | // 所有 DNA 由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。 4 | // 在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。 5 | // 编写一个函数来查找 DNA 分子中所有出现超多一次的10个字母长的序列(子串)。 6 | // 7 | // 示例: 8 | // 输入: s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 9 | // 输出: ["AAAAACCCCC", "CCCCCAAAAA"] 10 | // 11 | // 12 | 13 | 14 | /** 15 | * @param {string} s 16 | * @return {string[]} 17 | */ 18 | var findRepeatedDnaSequences = function(s) { 19 | let hash = {} 20 | for(let i = 0; i + 10 <= s.length; i++){ 21 | if(!hash[s.slice(i, i+10)]) hash[s.slice(i, i+10)] = 1 22 | else{ 23 | hash[s.slice(i, i+10)]++; 24 | } 25 | } 26 | 27 | let arr = [] 28 | for(let str in hash){ 29 | if(hash[str] >= 2){ 30 | arr.push(str) 31 | } 32 | } 33 | return arr; 34 | }; -------------------------------------------------------------------------------- /哈希表/204-easy-计算质数.js: -------------------------------------------------------------------------------- 1 | // 204 easy 计算质数 2 | 3 | // 统计所有小于非负整数 n 的质数的数量。 4 | // 5 | // 示例: 6 | // 输入: 10 7 | // 输出: 4 8 | // 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 9 | 10 | /** 11 | * @param {number} n 12 | * @return {number} 13 | */ 14 | var countPrimes = function(n) { 15 | let count = 0 16 | for(let i = 0; i < n; i++){ 17 | if (isPrime(i)){ 18 | count++; 19 | } 20 | } 21 | return count; 22 | }; 23 | 24 | 25 | var isPrime = function(n){ 26 | if(n <= 1) return false; 27 | if (n === 2) return true; 28 | for(let i = 2; i <= Math.sqrt(n); i++){ 29 | if (n % i === 0){ 30 | return false 31 | } 32 | } 33 | return true 34 | } 35 | 36 | console.log(countPrimes(10)) -------------------------------------------------------------------------------- /哈希表/3-medium-无重复字符的最长子串.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 滑动窗口解法 5 | * @param {string} s 6 | * @return {number} 7 | */ 8 | var lengthOfLongestSubstring = function(s) { 9 | // 特殊情况 10 | if (s.length === 1) return 1; 11 | if (s.length === 2) return s[0] === s[1] ? 1: 2; 12 | 13 | let arr = s.split('') 14 | let l = 0, r = 0 15 | let hash = {} 16 | let max = 0; 17 | while(l < arr.length && r < arr.length){ 18 | if (!hash[arr[r]]) { 19 | hash[arr[r]] = true; 20 | r++; 21 | } else { 22 | delete hash[arr[l]] 23 | l++; 24 | } 25 | if (max < Object.values(hash).length){ 26 | max = Object.values(hash).length 27 | } 28 | } 29 | return max; 30 | }; 31 | 32 | console.log(lengthOfLongestSubstring('abcabcbb')) 33 | console.log(lengthOfLongestSubstring('bbbbb')) 34 | console.log(lengthOfLongestSubstring('pwwkew')) -------------------------------------------------------------------------------- /哈希表/389-easy-找不同.js: -------------------------------------------------------------------------------- 1 | // 389 easy 找不同 2 | // 3 | // 给定两个字符串 s 和 t,它们只包含小写字母。 4 | // 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 5 | // 请找出在 t 中被添加的字母。 6 | // 7 | // 8 | // 示例: 9 | // 输入: 10 | // s = "abcd" 11 | // t = "abcde" 12 | // 13 | // 输出: 14 | // e 15 | // 16 | // 解释: 17 | // 'e' 是那个被添加的字母。 18 | 19 | 20 | /** 21 | * @param {string} s 22 | * @param {string} t 23 | * @return {character} 24 | */ 25 | var findTheDifference = function(s, t) { 26 | let hashT = {} 27 | for(let i = 0; i < t.length; i++){ 28 | if (!hashT[t[i]]) hashT[t[i]] = 1 29 | else hashT[t[i]]++; 30 | } 31 | 32 | let hashS = {} 33 | for(let i = 0; i < s.length; i++){ 34 | if (!hashS[s[i]]) hashS[s[i]] = 1 35 | else hashS[s[i]]++; 36 | } 37 | 38 | for(let key in hashT){ 39 | if(!hashS[key]) return key 40 | if (hashS[key] < hashT[key]) return key 41 | } 42 | }; 43 | 44 | console.log(findTheDifference('abcd', 'abcde')) -------------------------------------------------------------------------------- /哈希表/409-easy-最长回文串.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 如果字符都是成偶数出现,直接返回全厂;有奇数次出现的,只能取一次 5 | * @param {string} s 6 | * @return {number} 7 | */ 8 | var longestPalindrome = function(s) { 9 | let hash = {} 10 | for(let i = 0; i < s.length; i++){ 11 | if(!hash[s[i]])hash[s[i]]=1 12 | else{ 13 | hash[s[i]]++ 14 | } 15 | } 16 | 17 | let count = 0 18 | let useOdd = false; 19 | for(let key in hash){ 20 | if (hash[key] % 2 === 0){ 21 | count += hash[key] 22 | } else { 23 | if (!useOdd){ 24 | count += hash[key] 25 | useOdd = true 26 | } else { 27 | let a = hash[key] > 1 ? hash[key] - 1 : 0 28 | count += a; 29 | } 30 | } 31 | } 32 | return count; 33 | }; 34 | 35 | console.log(longestPalindrome('abccccdd')) -------------------------------------------------------------------------------- /哈希表/560-medium-和为K的子数组.js: -------------------------------------------------------------------------------- 1 | // 560 medium 和为K的子数组 2 | 3 | // 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。 4 | // 5 | // 示例 1 : 6 | // 输入:nums = [1,1,1], k = 2 7 | // 输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。 8 | // 说明 : 9 | // 数组的长度为 [1, 20,000]。 10 | // 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。 11 | // 12 | 13 | 14 | 15 | /** 16 | * 前缀和 哈希表 17 | * @param {number[]} nums 18 | * @param {number} k 19 | * @return {number} 20 | */ 21 | var subarraySum = function(nums, k) { 22 | let hash = {} 23 | hash[0] = 1 24 | let sum = 0 25 | let res=0 26 | for(let i = 0; i < nums.length; i++){ 27 | sum+= nums[i] 28 | res += hash[sum-k] ?hash[sum-k] : 0 29 | hash[sum] = (~~hash[sum]) + 1 30 | } 31 | return res 32 | }; 33 | 34 | console.log(subarraySum([1,1,1], 2)) -------------------------------------------------------------------------------- /哈希表/594-easy-最长和谐子序列.js: -------------------------------------------------------------------------------- 1 | // 594 easy 最长和谐子序列 2 | 3 | // 和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1。 4 | // 现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度。 5 | // 6 | // 示例 1: 7 | // 输入: [1,3,2,2,5,2,3,7] 8 | // 输出: 5 9 | // 原因: 最长的和谐数组是:[3,2,2,2,3]. 10 | // 说明: 输入的数组长度最大不超过20,000. 11 | 12 | 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number} 17 | */ 18 | var findLHS = function(nums) { 19 | let h = {} 20 | for(let i = 0; i < nums.length; i++){ 21 | if (!h[nums[i]]){ 22 | h[nums[i]] = 1 23 | }else{ 24 | h[nums[i]]++ 25 | } 26 | } 27 | 28 | let result = 0; 29 | for(let key in h){ 30 | if (h[Number(key) + 1 + '']){ 31 | result = Math.max(result, h[key] + h[Number(key) + 1 + '']) 32 | } 33 | } 34 | return result 35 | }; 36 | 37 | console.log(findLHS([1,3,2,2,5,2,3,7])) -------------------------------------------------------------------------------- /哈希表/645-easy-错误的集合.js: -------------------------------------------------------------------------------- 1 | // 645 easy 错误的集合 2 | 3 | // 集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。 4 | // 给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。 5 | // 6 | // 示例 1: 7 | // 输入: nums = [1,2,2,4] 8 | // 输出: [2,3] 9 | 10 | // 注意: 11 | // 给定数组的长度范围是 [2, 10000]。 12 | // 给定的数组是无序的。 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number[]} 17 | */ 18 | var findErrorNums = function(nums) { 19 | let hash = {} 20 | let repeatIndex 21 | let arr = [] 22 | for(let i = 1; i <= nums.length; i++){ 23 | arr.push(i) 24 | } 25 | for(let i = 0; i < nums.length; i++){ 26 | if (!hash[nums[i]]) { 27 | hash[nums[i]]=1 28 | arr.splice(arr.indexOf(nums[i]), 1) 29 | } else { 30 | repeatIndex = nums[i]; 31 | } 32 | 33 | } 34 | return [repeatIndex, arr[0]] 35 | }; 36 | 37 | console.log(findErrorNums([2,2])) -------------------------------------------------------------------------------- /哈希表/692-medium-前K个高频单词.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {string[]} words 5 | * @param {number} k 6 | * @return {string[]} 7 | */ 8 | var topKFrequent = function(words, k) { 9 | let hash = {} 10 | for(let i = 0; i < words.length; i++){ 11 | hash[words[i]] = ~~(hash[words[i]]) + 1 12 | } 13 | 14 | let kv = Object.entries(hash) 15 | kv.sort((a, b) => { 16 | if(a[1] < b[1]){ 17 | return 1; 18 | }else{ 19 | return -1; 20 | } 21 | }) 22 | kv = kv.slice(0, k) 23 | kv.sort((a,b) => { 24 | return a[0] - b[0] 25 | }) 26 | 27 | let arr = [] 28 | for(let i = 0; i < kv.length; i++){ 29 | arr.push(kv[i][0]) 30 | } 31 | return arr; 32 | }; 33 | 34 | 35 | console.log(topKFrequent(["i", "love", "leetcode", "i", "love", "coding"], 2)) -------------------------------------------------------------------------------- /哈希表/739-medium-每日温度.js: -------------------------------------------------------------------------------- 1 | // 739 medium 每日温度 2 | // 跟496题解法一样 3 | // 4 | // 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。 5 | // 例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。 6 | // 提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。 7 | // 8 | 9 | 10 | /** 11 | * 暴力法 12 | * @param {number[]} T 13 | * @return {number[]} 14 | */ 15 | var dailyTemperatures = function(T) { 16 | let resultArr = [] 17 | for(let i = 0; i < T.length; i++){ 18 | let flag = false 19 | for(let j = i + 1; j < T.length; j++){ 20 | if (T[j] > T[i]){ 21 | flag = true 22 | resultArr.push(j - i) 23 | break; 24 | } 25 | } 26 | if (!flag){ 27 | resultArr.push(0) 28 | } 29 | } 30 | return resultArr; 31 | }; -------------------------------------------------------------------------------- /哈希表/771-easy-石头与宝石.js: -------------------------------------------------------------------------------- 1 | // 771 easy 石头与宝石 2 | // 3 | // 给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头。  4 | // S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。 5 | // J 中的字母不重复,J 和 S中的所有字符都是字母。字母区分大小写,因此"a"和"A"是不同类型的石头。 6 | // 7 | // 示例 1: 8 | // 输入: J = "aA", S = "aAAbbbb" 9 | // 输出: 3 10 | 11 | // 示例 2: 12 | // 输入: J = "z", S = "ZZ" 13 | // 输出: 0 14 | 15 | // 注意: 16 | // S 和 J 最多含有50个字母。 17 | //  J 中的字符不重复。 18 | 19 | /** 20 | * @param {string} J 21 | * @param {string} S 22 | * @return {number} 23 | */ 24 | var numJewelsInStones = function(J, S) { 25 | let typeArr = J.split('') 26 | let count = 0 27 | for(let i = 0; i < S.length; i++){ 28 | if (typeArr.includes(S[i])){ 29 | count++ 30 | } 31 | } 32 | return count 33 | }; 34 | 35 | console.log(numJewelsInStones('aA', 'aAAbbbb')) 36 | console.log(numJewelsInStones('z', 'ZZ')) -------------------------------------------------------------------------------- /哈希表/957-medium-N天后的牢房.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {number[]} cells 5 | * @param {number} N 6 | * @return {number[]} 7 | */ 8 | var prisonAfterNDays = function(cells, N) { 9 | 10 | for(let j = 1; j <= N; j++){ 11 | 12 | let fn = (newArr) => { 13 | for(let i = 1; i < newArr.length - 1; i++){ 14 | if((newArr[i-1] === 0 && newArr[i+1] === 0) || 15 | (newArr[i-1] === 1 && newArr[i+1] === 1)){ 16 | newArr[i] = 1 17 | } else { 18 | newArr[i] = 0; 19 | } 20 | } 21 | return newArr 22 | } 23 | 24 | if(j === N){ 25 | return newArr 26 | } 27 | } 28 | }; 29 | 30 | console.log(prisonAfterNDays([0,1,0,1,1,0,0,1], 1)) -------------------------------------------------------------------------------- /哈希表/961-easy-重复N次的元素.js: -------------------------------------------------------------------------------- 1 | // 961 easy 重复N次的元素 2 | // 3 | // 在大小为 2N 的数组 A 中有 N+1 个不同的元素,其中有一个元素重复了 N 次。 4 | // 返回重复了 N 次的那个元素。 5 | // 6 | // 7 | // 示例 1: 8 | // 输入:[1,2,3,3] 9 | // 输出:3 10 | 11 | // 示例 2: 12 | // 输入:[2,1,2,5,3,2] 13 | // 输出:2 14 | 15 | // 示例 3: 16 | // 输入:[5,1,5,2,5,3,5,4] 17 | // 输出:5 18 | // 19 | // 提示: 20 | // 4 <= A.length <= 10000 21 | // 0 <= A[i] < 10000 22 | // A.length 为偶数 23 | 24 | /** 25 | * @param {number[]} A 26 | * @return {number} 27 | */ 28 | var repeatedNTimes = function(A) { 29 | let len = A.length / 2; 30 | let hash = {} 31 | for(let i = 0; i < A.length; i++){ 32 | if (!hash[A[i]])hash[A[i]]=1 33 | else{ 34 | hash[A[i]]++ 35 | 36 | if (hash[A[i]] === len){ 37 | return A[i] 38 | } 39 | } 40 | } 41 | }; 42 | 43 | console.log(repeatedNTimes([1,2,3,3])) -------------------------------------------------------------------------------- /哈希表/出现频率/451-medium-根据字符出现频率排序.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * @param {string} s 6 | * @return {string} 7 | */ 8 | var frequencySort = function(s) { 9 | let h = {} 10 | for(let i = 0; i < s.length; i++){ 11 | if (!h[s[i]]) { 12 | h[s[i]] = 1 13 | } else { 14 | h[s[i]]++; 15 | } 16 | } 17 | 18 | // 构造二维数组 19 | let arr = [] 20 | for(let key in h){ 21 | let a = new Array(h[key]) 22 | a.fill(key) 23 | arr.push(a); 24 | } 25 | 26 | // 排序 27 | arr.sort((a, b) => { 28 | return a.length > b.length ? -1: 1 29 | }) 30 | 31 | // 拼接字符串 32 | let str = '' 33 | for(let i = 0; i < arr.length; i++){ 34 | str += arr[i].join('') 35 | } 36 | return str; 37 | }; 38 | 39 | console.log(frequencySort('tree')) -------------------------------------------------------------------------------- /哈希表/字母异位词/438-easy-找到字符串中的所有字母异位词.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | /** 6 | * @param {string} s 7 | * @param {string} p 8 | * @return {number[]} 9 | */ 10 | var findAnagrams = function(s, p) { 11 | if(!p) return [] 12 | let arr = [] 13 | let width = p.length; 14 | for(let i = 0; i < s.length; i++){ 15 | if (isAnagram2(s.slice(i, i + width), p)){ 16 | arr.push(i) 17 | } 18 | } 19 | return arr 20 | }; 21 | 22 | console.log(findAnagrams('cbaebabacd', 'abc')) 23 | 24 | -------------------------------------------------------------------------------- /哈希表题目.md: -------------------------------------------------------------------------------- 1 | ## 哈希表 2 | 3 | * 3 medium 无重复字符的最长子串 4 | * 36 medium 有效的数独 5 | * 49 medium 字母异位词分组 6 | * 136 easy 只出现一次的数字 7 | * 187 medium 重复的DNA序列 8 | * 204 easy 计算质数 9 | * 205 easy 同构字符串 10 | * 219 easy 存在重复元素2 11 | * 242 easy 有效的字母异位词 12 | * 347 medium 前K个高频元素 13 | * 380 medium 常数时间插入、删除和获取随机元素 14 | * 389 easy 找不同 15 | * 409 easy 最长回文串 16 | * 438 easy 找到字符串中的所有字母异位词 17 | * 451 medium 根据字符出现频率排序 18 | * 454 medium 四数相加 II 19 | * 500 easy 键盘行 20 | * 506 easy 相对名次 21 | * 547 medium 并查集 22 | * 560 medium 和为K的子数组 23 | * 575 easy 分糖果 24 | * 594 easy 最长和谐子序列 25 | * 599 easy 两个列表的最小索引总和 26 | * 645 easy 错误的集合 27 | * 648 medium 单词替换 28 | * 677 medium 键值映射 29 | * 684 medium 冗余连接 30 | * 692 medium 前K个高频单词 31 | * 706 easy 设计哈希集合 32 | * 739 medium 每日温度 33 | * 748 easy 最短完整词 34 | * 771 easy 石头与宝石 35 | * 781 medium 森林中的兔子 36 | * 811 easy 子域名访问计数 37 | * 884 easy 两句话中的不常见单词 38 | * 953 easy 验证外星语词典 39 | * 957 medium N天后的牢房 40 | * 961 easy 重复N次的元素 41 | * 1078 easy bigram分词 42 | * 1189 easy 气球的最大数量 43 | * 1287 easy 有序数组中出现次数超过25%的元素 -------------------------------------------------------------------------------- /字符串/1016-medium-子串能表示从1到N数字的二进制串.js: -------------------------------------------------------------------------------- 1 | // 1016 medium 子串能表示从 1 到 N 数字的二进制串 2 | 3 | //给定一个二进制字符串 S(一个仅由若干 '0' 和 '1' 构成的字符串)和一个正整数 N, 4 | // 如果对于从 1 到 N 的每个整数 X,其二进制表示都是 S 的子串,就返回 true,否则返回 false。 5 | // 6 | // 7 | // 示例 1: 8 | // 输入:S = "0110", N = 3 9 | // 输出:true 10 | // 示例 2: 11 | // 输入:S = "0110", N = 4 12 | // 输出:false 13 | //   14 | // 提示: 15 | // 1 <= S.length <= 1000 16 | // 1 <= N <= 10^9 17 | // 18 | 19 | /** 20 | * @param {string} S 21 | * @param {number} N 22 | * @return {boolean} 23 | */ 24 | var queryString = function(S, N) { 25 | // 逐个遍历每个数,判断是否是S的子串 26 | for(let i = 1; i <= N; i++){ 27 | let binary = i.toString(2); 28 | if(S.indexOf(binary) === -1){ 29 | return false; 30 | } 31 | } 32 | return true; 33 | }; 34 | 35 | console.log(queryString('0110', 4)) -------------------------------------------------------------------------------- /字符串/1071-easy-字符串的最大公因子.js: -------------------------------------------------------------------------------- 1 | // 1071 easy 字符串的最大公因子 2 | 3 | // 对于字符串 S 和 T,只有在 S = T + ... + T(T 与自身连接 1 次或多次)时,我们才认定 “T 能除尽 S”。 4 | // 返回字符串 X,要求满足 X 能除尽 str1 且 X 能除尽 str2。 5 | // 6 | 7 | // 示例 1: 8 | // 输入:str1 = "ABCABC", str2 = "ABC" 9 | // 输出:"ABC" 10 | // 示例 2: 11 | // 输入:str1 = "ABABAB", str2 = "ABAB" 12 | // 输出:"AB" 13 | // 示例 3: 14 | // 输入:str1 = "LEET", str2 = "CODE" 15 | // 输出:"" 16 | 17 | 18 | /** 19 | * @param {string} str1 20 | * @param {string} str2 21 | * @return {string} 22 | */ 23 | var gcdOfStrings = function(str1, str2) { 24 | if(str1 + str2 !== str2 + str1) return ''; 25 | let gcd = (a, b) => { 26 | return b === 0 ? a: gcd(b, a % b); 27 | } 28 | return str1.slice(0, gcd(str1.length, str2.length)); 29 | }; 30 | 31 | console.log(gcdOfStrings('ABCABC', 'ABC')) -------------------------------------------------------------------------------- /字符串/1108-easy-IP地址无效化.js: -------------------------------------------------------------------------------- 1 | // 给你一个有效的 IPv4 地址 address,返回这个 IP 地址的无效化版本。 2 | // 所谓无效化 IP 地址,其实就是用 "[.]" 代替了每个 "."。 3 | // 4 | // 5 | // 示例 1: 6 | // 输入:address = "1.1.1.1" 7 | // 输出:"1[.]1[.]1[.]1" 8 | 9 | // 示例 2: 10 | // 输入:address = "255.100.50.0" 11 | // 输出:"255[.]100[.]50[.]0" 12 | // 13 | // 提示: 14 | // 给出的 address 是一个有效的 IPv4 地址 15 | 16 | 17 | /** 18 | * @param {string} address 19 | * @return {string} 20 | */ 21 | var defangIPaddr = function(address) { 22 | let reg = /\./g 23 | address = address.replace(reg, '[.]') 24 | return address 25 | }; 26 | 27 | console.log(defangIPaddr("1.1.1.1")) -------------------------------------------------------------------------------- /字符串/125-easy-验证回文串.js: -------------------------------------------------------------------------------- 1 | // easy 126 验证回文串 2 | 3 | // 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 4 | // 说明:本题中,我们将空字符串定义为有效的回文串。 5 | // 6 | // 示例 1: 7 | // 输入: "A man, a plan, a canal: Panama" 8 | // 输出: true 9 | 10 | // 示例 2: 11 | // 输入: "race a car" 12 | // 输出: false 13 | 14 | 15 | /** 16 | * @param {string} s 17 | * @return {boolean} 18 | */ 19 | var isPalindrome = function(s) { 20 | if(s === '')return true; 21 | 22 | let arr = [] 23 | for(let i = 0; i < s.length; i++){ 24 | if(/[0-9a-zA-Z]/.test(s[i])){ 25 | arr.push(s[i].toLowerCase()) 26 | } 27 | } 28 | 29 | let l = 0, r = arr.length - 1; 30 | while(l < r){ 31 | if(arr[l]!== arr[r]){ 32 | return false; 33 | } 34 | l++; 35 | r--; 36 | } 37 | return true; 38 | }; 39 | 40 | console.log(isPalindrome("A man, a plan, a canal: Panama")) 41 | -------------------------------------------------------------------------------- /字符串/1374.-easy-生成每种字符都是奇数个的字符串.js: -------------------------------------------------------------------------------- 1 | // 1374. easy 生成每种字符都是奇数个的字符串 2 | 3 | // 给你一个整数 n,请你返回一个含 n 个字符的字符串,其中每种字符在该字符串中都恰好出现 奇数次 。 4 | // 返回的字符串必须只含小写英文字母。如果存在多个满足题目要求的字符串,则返回其中任意一个即可。 5 | // 6 | // 示例 1: 7 | // 输入:n = 4 8 | // 输出:"pppz" 9 | // 解释:"pppz" 是一个满足题目要求的字符串,因为 'p' 出现 3 次,且 'z' 出现 1 次。 10 | // 当然,还有很多其他字符串也满足题目要求,比如:"ohhh" 和 "love"。 11 | // 示例 2: 12 | // 输入:n = 2 13 | // 输出:"xy" 14 | // 解释:"xy" 是一个满足题目要求的字符串,因为 'x' 和 'y' 各出现 1 次。 15 | // 当然,还有很多其他字符串也满足题目要求,比如:"ag" 和 "ur"。 16 | // 示例 3: 17 | // 输入:n = 7 18 | // 输出:"holasss" 19 | //   20 | // 提示: 21 | // 1 <= n <= 500 22 | 23 | var generateTheString = function(n) { 24 | if(n===0)return ''; 25 | if(n===1)return 'a'; 26 | let res = ''; 27 | let to = 'abcdefghijklmnopqrstuvwxyz'; 28 | if (n % 2 === 0){ 29 | res += 'b'; 30 | for(let i = 1; i <= n-1; i++){ 31 | res += 'a'; 32 | } 33 | }else{ 34 | for(let i = 1; i <= n; i++){ 35 | res += 'a'; 36 | } 37 | } 38 | return res; 39 | }; -------------------------------------------------------------------------------- /字符串/151-medium-翻转字符串里的单词.js: -------------------------------------------------------------------------------- 1 | // 151 medium 翻转字符串里的单词 2 | 3 | // 给定一个字符串,逐个翻转字符串中的每个单词。 4 | // 5 | // 示例 1: 6 | // 输入: "the sky is blue" 7 | // 输出: "blue is sky the" 8 | // 9 | // 示例 2: 10 | // 输入: "  hello world!  " 11 | // 输出: "world! hello" 12 | // 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 13 | // 14 | // 示例 3: 15 | // 输入: "a good   example" 16 | // 输出: "example good a" 17 | // 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 18 | //   19 | // 说明: 20 | // 无空格字符构成一个单词。 21 | // 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 22 | // 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 23 | 24 | 25 | /** 26 | * @param {string} s 27 | * @return {string} 28 | */ 29 | var reverseWords = function(s) { 30 | let arr = s.split(' ') 31 | for(let i = arr.length - 1; i >= 0; i--){ 32 | if(/\s/.test(arr[i]) || arr[i] === '' || arr[i] === ' ') { 33 | arr.splice(i, 1) 34 | } 35 | } 36 | return arr.reverse().join(' ') 37 | }; 38 | 39 | // console.log(reverseWords('a good   example')) 40 | console.log(reverseWords("babad")) -------------------------------------------------------------------------------- /字符串/28-easy-实现strStr.js: -------------------------------------------------------------------------------- 1 | // 28 easy 2 | 3 | // 实现 strStr() 函数。 4 | // 5 | // 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1。 6 | // 7 | // 示例 1: 8 | // 输入: haystack = "hello", needle = "ll" 9 | // 输出: 2 10 | 11 | // 示例 2: 12 | // 输入: haystack = "aaaaa", needle = "bba" 13 | // 输出: -1 14 | 15 | // 说明: 16 | // 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 17 | // 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 18 | // 19 | 20 | 21 | /** 22 | * @param {string} haystack 23 | * @param {string} needle 24 | * @return {number} 25 | */ 26 | var strStr = function(haystack, needle) { 27 | return haystack.indexOf(needle) 28 | }; 29 | 30 | console.log(strStr('hello', 'll')) 31 | console.log(strStr('aaaa', 'ad')) -------------------------------------------------------------------------------- /字符串/3-noRepeatCharLongestSubStr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 返回一个字符串无重复子串的长度 3 | * eg abcabccabba 3 abc 4 | * eg bebcwecdt 5 wecdt 5 | */ 6 | function getLongestSubStrLength(str){ 7 | // 空串返回0 8 | if (!str.length) return 0 9 | 10 | let resultArr = [] 11 | for(let i = 0; i < str.length; i++){ 12 | if (!resultArr.includes(str[i])){ 13 | resultArr.push(str[i]) 14 | } 15 | let index = resultArr.indexOf(str[i]) 16 | resultArr.splice(0, index) 17 | } 18 | return resultArr.length 19 | } 20 | 21 | 22 | console.log(getLongestSubStrLength('abcabccabba')) 23 | console.log(getLongestSubStrLength('bebcwecdt')) 24 | -------------------------------------------------------------------------------- /字符串/344-反转字符串.js: -------------------------------------------------------------------------------- 1 | // 344 easy 反转字符串 2 | // 3 | // 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 4 | // 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 5 | // 你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。 6 | // 7 | //   8 | // 输入:["h","e","l","l","o"] 9 | // 输出:["o","l","l","e","h"] 10 | 11 | // 示例 2: 12 | // 输入:["H","a","n","n","a","h"] 13 | // 输出:["h","a","n","n","a","H"] 14 | 15 | /** 16 | * @return {void} Do not return anything, modify s in-place instead. 17 | */ 18 | var reverseString = function(s) { 19 | if (!s.length) return []; 20 | if(s.length === 1) return s; 21 | 22 | let prev = 0; 23 | let next = s.length - 1; 24 | 25 | while(true){ 26 | if (next - prev === 0 || next - prev === -1) { 27 | return s; 28 | } 29 | [s[prev], s[next]] = [s[next], s[prev]] 30 | next--; 31 | prev++; 32 | } 33 | }; 34 | 35 | console.log(reverseString(["H","a","n","n","a","h"])) 36 | console.log(reverseString(["h","e","l","l","o"])) -------------------------------------------------------------------------------- /字符串/383-赎金信.js: -------------------------------------------------------------------------------- 1 | // easy 383 赎金信 2 | // 3 | // 给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成。如果可以构成,返回 true ;否则返回 false。 4 | // 5 | // (题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。) 6 | // 7 | // 注意: 8 | // 9 | // 你可以假设两个字符串均只含有小写字母。 10 | // 11 | // canConstruct("a", "b") -> false 12 | // canConstruct("aa", "ab") -> false 13 | // canConstruct("aa", "aab") -> true 14 | 15 | 16 | /** 17 | * @param {string} ransomNote 18 | * @param {string} magazine 19 | * @return {boolean} 20 | */ 21 | var canConstruct = function(ransomNote, magazine) { 22 | let arr = magazine.split('') 23 | for(let i = 0; i < ransomNote.length; i++){ 24 | let index = arr.indexOf(ransomNote[i]) 25 | if(index === -1){ 26 | return false 27 | } else { 28 | arr.splice(index, 1) 29 | } 30 | } 31 | return true 32 | }; 33 | 34 | console.log(canConstruct("fihjjjjei", "hjibagacbhadfaefdjaeaebgi")) -------------------------------------------------------------------------------- /字符串/387-easy-字符串中的第一个唯一字符.js: -------------------------------------------------------------------------------- 1 | // easy 387 字符串中的第一个唯一字符 2 | // 3 | // 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 4 | // 5 | // 案例: 6 | // s = "leetcode" 7 | // 返回 0. 8 | // 9 | // s = "loveleetcode", 10 | // 返回 2. 11 | 12 | /** 13 | * @param {string} s 14 | * @return {number} 15 | */ 16 | var firstUniqChar = function(s) { 17 | let hash = {} 18 | for(let i = 0; i < s.length; i++){ 19 | if(!hash[s[i]]) hash[s[i]]=1 20 | else{ 21 | hash[s[i]]++ 22 | } 23 | } 24 | 25 | let index = 0 26 | while(index < s.length){ 27 | if (hash[s[index]] === 1) return index; 28 | else{ 29 | index++; 30 | } 31 | } 32 | return -1 33 | }; 34 | 35 | 36 | 37 | console.log(firstUniqChar('leetcode')); 38 | console.log(firstUniqChar('loveleetcode')); 39 | console.log(firstUniqChar('cc')); 40 | 41 | -------------------------------------------------------------------------------- /字符串/392-easy-判断子序列.js: -------------------------------------------------------------------------------- 1 | // 392 easy 判断子序列 2 | 3 | // 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 4 | // 你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。 5 | // 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。 6 | // (例如,"ace"是"abcde"的一个子序列,而"aec"不是)。 7 | // 8 | // 示例 1: 9 | // s = "abc", t = "ahbgdc" 10 | // 返回 true. 11 | 12 | // 示例 2: 13 | // s = "axc", t = "ahbgdc" 14 | // 返回 false. 15 | 16 | 17 | /** 18 | * @param {string} s 19 | * @param {string} t 20 | * @return {boolean} 21 | */ 22 | var isSubsequence = function(s, t) { 23 | if(!s)return true 24 | 25 | let index = 0 26 | for(let i = 0; i < t.length; i++){ 27 | if(t[i] === s[index]){ 28 | if(index === s.length-1){ 29 | return true; 30 | } 31 | index++; 32 | } 33 | } 34 | return false; 35 | }; -------------------------------------------------------------------------------- /字符串/434-easy-字符串中的单词数.js: -------------------------------------------------------------------------------- 1 | 2 | // 434 easy 字符串中的单词数 3 | 4 | // 统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。 5 | // 6 | // 请注意,你可以假定字符串里不包括任何不可打印的字符。 7 | // 8 | // 示例: 9 | // 10 | // 输入: "Hello, my name is John" 11 | // 输出: 5 12 | // 13 | 14 | 15 | /** 16 | * @param {string} s 17 | * @return {number} 18 | */ 19 | var countSegments = function(s) { 20 | let arr = s.split(' ') 21 | let count = 0 22 | for(let i = 0; i < arr.length; i++){ 23 | if (arr[i]){ 24 | count++ 25 | } 26 | } 27 | return count; 28 | }; 29 | 30 | // console.log(countSegments("Hello, my name is John")) // 5 31 | console.log(countSegments(", , , , a, eaefa")) // 6 -------------------------------------------------------------------------------- /字符串/520-检测大写字母.js: -------------------------------------------------------------------------------- 1 | // 520 easy 检测大写字母 2 | // 3 | // 给定一个单词,你需要判断单词的大写使用是否正确。 4 | // 我们定义,在以下情况时,单词的大写用法是正确的: 5 | // 6 | // 全部字母都是大写,比如"USA"。 7 | // 单词中所有字母都不是大写,比如"leetcode"。 8 | // 如果单词不只含有一个字母,只有首字母大写, 比如 "Google"。 9 | // 否则,我们定义这个单词没有正确使用大写字母。 10 | // 11 | // 示例 1: 12 | // 输入: "USA" 13 | // 输出: True 14 | 15 | // 示例 2: 16 | // 输入: "FlaG" 17 | // 输出: False 18 | 19 | // 注意: 输入是由大写和小写拉丁字母组成的非空单词。 20 | 21 | /** 22 | * @param {string} word 23 | * @return {boolean} 24 | */ 25 | var detectCapitalUse = function(word) { 26 | if (word.toUpperCase() === word || word.toLowerCase() === word){ 27 | return true; 28 | } else if(word[0].toUpperCase() === word[0] 29 | && word.substring(1).toLowerCase() === word.substring(1)){ 30 | return true 31 | } 32 | return false 33 | }; -------------------------------------------------------------------------------- /字符串/521-最长特殊序列.js: -------------------------------------------------------------------------------- 1 | // easy 521 2 | 3 | // 给定两个字符串,你需要从这两个字符串中找出最长的特殊序列。最长特殊序列定义如下:该序列为某字符串独有的最长子序列(即不能是其他字符串的子序列)。 4 | 5 | // 子序列可以通过删去字符串中的某些字符实现,但不能改变剩余字符的相对顺序。空序列为所有字符串的子序列,任何字符串为其自身的子序列。 6 | // 输入为两个字符串,输出最长特殊序列的长度。如果不存在,则返回 -1。 7 | // 8 | // 示例 : 9 | // 输入: "aba", "cdc" 10 | // 输出: 3 11 | // 解析: 最长特殊序列可为 "aba" (或 "cdc") 12 | 13 | // 说明: 14 | // 两个字符串长度均小于100。 15 | // 字符串中的字符仅含有 'a'~'z'。 16 | 17 | 18 | /** 19 | * @param {string} a 20 | * @param {string} b 21 | * @return {number} 22 | */ 23 | var findLUSlength = function(a, b) { 24 | if (a.length !== b.length) return a.length > b.length ? a.length : b.length; 25 | if (a === b) { 26 | return -1 27 | } else { 28 | // 或者b的长度 29 | return a.length 30 | } 31 | }; -------------------------------------------------------------------------------- /字符串/5396-easy-连续字符.js: -------------------------------------------------------------------------------- 1 | 2 | // 5396 easy 连续字符 3 | 4 | //给你一个字符串 s ,字符串的「能量」定义为:只包含一种字符的最长非空子字符串的长度。 5 | // 请你返回字符串的能量。 6 | 7 | //示例 1: 8 | // 输入:s = "leetcode" 9 | // 输出:2 10 | // 解释:子字符串 "ee" 长度为 2 ,只包含字符 'e' 。 11 | // 示例 2: 12 | // 输入:s = "abbcccddddeeeeedcba" 13 | // 输出:5 14 | // 解释:子字符串 "eeeee" 长度为 5 ,只包含字符 'e' 。 15 | // 示例 3: 16 | // 输入:s = "triplepillooooow" 17 | // 输出:5 18 | // 示例 4: 19 | // 输入:s = "hooraaaaaaaaaaay" 20 | // 输出:11 21 | // 示例 5: 22 | // 输入:s = "tourist" 23 | // 输出:1 24 | // 25 | // 提示: 26 | // 1 <= s.length <= 500 27 | // s 只包含小写英文字母。 28 | 29 | 30 | var maxPower = function(s) { 31 | let ss = 1 32 | let res = 1 33 | for(let i = 0; i < s.length-1; i++){ 34 | if (s[i] === s[i+1]){ 35 | ss += 1 36 | }else{ 37 | ss = 1; 38 | } 39 | res = Math.max(ss, res) 40 | } 41 | return res 42 | }; 43 | 44 | console.log(maxPower("leeeeetcode")) -------------------------------------------------------------------------------- /字符串/551-easy-学生出勤记录1.js: -------------------------------------------------------------------------------- 1 | // 551 easy 学生出勤记录1 2 | // 3 | // 给定一个字符串来代表一个学生的出勤记录,这个记录仅包含以下三个字符: 4 | // 5 | // 'A' : Absent,缺勤 6 | // 'L' : Late,迟到 7 | // 'P' : Present,到场 8 | // 如果一个学生的出勤记录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),那么这个学生会被奖赏。 9 | // 你需要根据这个学生的出勤记录判断他是否会被奖赏。 10 | // 11 | // 示例 1: 12 | // 输入: "PPALLP" 13 | // 输出: True 14 | 15 | // 示例 2: 16 | // 输入: "PPALLL" 17 | // 输出: False 18 | // 19 | 20 | 21 | /** 22 | * @param {string} s 23 | * @return {boolean} 24 | */ 25 | var checkRecord = function(s) { 26 | let aCount = 0 27 | for(let i = 0; i < s.length; i++){ 28 | if(s[i] === 'A') aCount++; 29 | } 30 | 31 | let hasGtThreeL = false; // 有没有连续3个及以上L 32 | for(let i = 0; i < s.length - 2; i++){ 33 | if (s[i] === 'L' && s[i+1] === 'L' && s[i+2] === 'L'){ 34 | hasGtThreeL = true 35 | } 36 | } 37 | 38 | 39 | return (!hasGtThreeL && aCount <= 1) 40 | }; 41 | 42 | // console.log(checkRecord('PPALLP')) 43 | console.log(checkRecord('LLL')) -------------------------------------------------------------------------------- /字符串/553-最优除法.js: -------------------------------------------------------------------------------- 1 | // 553 medium 最优除法 2 | // 3 | // 给定一组正整数,相邻的整数之间将会进行浮点除法操作。例如, [2,3,4] -> 2 / 3 / 4 。 4 | // 但是,你可以在任意位置添加任意数目的括号,来改变算数的优先级。你需要找出怎么添加括号,才能得到最大的结果,并且返回相应的字符串格式的表达式。你的表达式不应该含有冗余的括号。 5 | // 6 | // 示例: 7 | // 输入: [1000,100,10,2] 8 | // 输出: "1000/(100/10/2)" 9 | // 解释: 10 | // 1000/(100/10/2) = 1000/((100/10)/2) = 200 11 | // 但是,以下加粗的括号 "1000/((100/10)/2)" 是冗余的, 12 | // 因为他们并不影响操作的优先级,所以你需要返回 "1000/(100/10/2)"。 13 | // 14 | // 其他用例: 15 | // 1000/(100/10)/2 = 50 16 | // 1000/(100/(10/2)) = 50 17 | // 1000/100/10/2 = 0.5 18 | // 1000/100/(10/2) = 2 19 | 20 | // 说明: 21 | // 输入数组的长度在 [1, 10] 之间。 22 | // 数组中每个元素的大小都在 [2, 1000] 之间。 23 | // 每个测试用例只有一个最优除法解。 24 | 25 | 26 | /** 27 | * @param {number[]} nums 28 | * @return {string} 29 | */ 30 | var optimalDivision = function(nums) { 31 | if (nums.length === 1) return `${nums[0]}` 32 | if (nums.length === 2) return `${nums[0]}/${nums[1]}` 33 | return `${nums[0]}/(` + nums.slice(1).join('/') + ')' 34 | }; 35 | 36 | console.log(optimalDivision([1000,100,10,2])) 37 | -------------------------------------------------------------------------------- /字符串/557-反转字符串中的单词.js: -------------------------------------------------------------------------------- 1 | 2 | // 557 反转字符串中的单词 3 | 4 | /* 5 | 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 6 | 7 | 示例 1: 8 | 9 | 输入: "Let's take LeetCode contest" 10 | 输出: "s'teL ekat edoCteeL tsetnoc" 11 | 注意:在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。 12 | */ 13 | 14 | 15 | /** 16 | * @param {string} s 17 | * @return {string} 18 | */ 19 | var reverseWords = function(s) { 20 | let arr = s.split(' ') 21 | arr = arr.map((item, index) => { 22 | return item.split('').reverse().join('') 23 | }) 24 | return arr.join(' '); 25 | }; 26 | 27 | console.log(reverseWords("Let's take LeetCode contest")) 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /字符串/58-最后一个单词长度.js: -------------------------------------------------------------------------------- 1 | // easy 58 最后一个单词长度 2 | 3 | // 给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度。 4 | // 如果不存在最后一个单词,请返回 0 。 5 | // 6 | // 说明:一个单词是指由字母组成,但不包含任何空格的字符串。 7 | // 8 | // 示例: 9 | // 输入: "Hello World" 10 | // 输出: 5 11 | 12 | 13 | 14 | /** 15 | * @param {string} s 16 | * @return {number} 17 | */ 18 | var lengthOfLastWord = function(s) { 19 | let arr = s.trim().split(" ") 20 | return arr[arr.length - 1].length 21 | }; -------------------------------------------------------------------------------- /字符串/680-easy-验证回文字符串2.js: -------------------------------------------------------------------------------- 1 | // 680. 验证回文字符串Ⅱ easy 2 | 3 | // 给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。 4 | // 5 | // 示例 1: 6 | // 输入: "aba" 7 | // 输出: True 8 | // 示例 2: 9 | // 输入: "abca" 10 | // 输出: True 11 | // 解释: 你可以删除c字符。 12 | // 注意: 13 | // 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。 14 | 15 | /** 16 | * @param {string} s 17 | * @return {boolean} 18 | */ 19 | var validPalindrome = function(s) { 20 | let l = 0,r = s.length-1 21 | 22 | // 再继续循环下去 23 | let fn = (s, l, r) => { 24 | while(l <= r){ 25 | if(s[l] !== s[r]){ 26 | return false; 27 | } 28 | l++;r--; 29 | } 30 | return true; 31 | }; 32 | while(l <= r){ 33 | if(s[l] !== s[r]){ 34 | return fn(s, l+1, r) || fn(s, l, r-1); 35 | } 36 | l++; r--; 37 | } 38 | return true; 39 | }; 40 | 41 | console.log(validPalindrome('abc')) -------------------------------------------------------------------------------- /字符串/680-easy-验证回文字符串Ⅱ.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * ❎ 5 | * @param {string} s 6 | * @return {boolean} 7 | */ 8 | var validPalindrome = function(s) { 9 | let diffCount = 0 10 | let l = 0,r = s.length-1 11 | while(l < r){ 12 | if(s[l] !== s[r]){ 13 | diffCount++; 14 | } 15 | l++; 16 | r--; 17 | } 18 | return diffCount <= 1 19 | }; 20 | 21 | console.log(validPalindrome('abca')) -------------------------------------------------------------------------------- /字符串/686-easy-重复叠加字符串匹配.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * @param {string} A 6 | * @param {string} B 7 | * @return {number} 8 | */ 9 | var repeatedStringMatch = function(A, B) { 10 | let times = 1; 11 | while(true){ 12 | let temp = A.repeat(times); 13 | if(temp.indexOf(B) > -1){ 14 | return times; 15 | }else{ 16 | if(temp.length > 2 * B.length){ 17 | return false; 18 | } 19 | } 20 | times++; 21 | } 22 | }; 23 | 24 | 25 | console.log(repeatedStringMatch('abcd', "cdabcdab")) 26 | -------------------------------------------------------------------------------- /字符串/7-easy-整数反转.js: -------------------------------------------------------------------------------- 1 | // easy 7 整数反转 2 | 3 | // 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 4 | // 5 | // 示例 1: 6 | // 输入: 123 7 | // 输出: 321 8 | 9 | // 示例 2: 10 | // 输入: -123 11 | // 输出: -321 12 | 13 | // 示例 3: 14 | // 输入: 120 15 | // 输出: 21 16 | // 注意: 17 | // 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231,  231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 18 | 19 | 20 | /** 21 | * @param {number} x 22 | * @return {number} 23 | */ 24 | var reverse = function(x) { 25 | let arr = (x + '').split(''); 26 | let res 27 | if(arr[0] === '-'){ 28 | res = +('-' + arr.slice(1).reverse().join('')) 29 | } else { 30 | res = arr.reverse().join('') / 1 31 | } 32 | if (res > Math.pow(2,31) -1 || res < - Math.pow(2, 31)){ 33 | return 0 34 | }else { 35 | return res; 36 | } 37 | }; -------------------------------------------------------------------------------- /字符串/709-easy-转换成小写字母.js: -------------------------------------------------------------------------------- 1 | // 709 easy 转换成小写字母 2 | 3 | 4 | // 实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。 5 | // 6 | // 示例 1: 7 | // 输入: "Hello" 8 | // 输出: "hello" 9 | 10 | // 示例 2: 11 | // 输入: "here" 12 | // 输出: "here" 13 | 14 | // 示例 3: 15 | // 输入: "LOVELY" 16 | // 输出: "lovely" 17 | 18 | 19 | 20 | /** 21 | * @param {string} str 22 | * @return {string} 23 | */ 24 | var toLowerCase = function(str) { 25 | return str.toLowerCase() 26 | }; -------------------------------------------------------------------------------- /字符串/lc-longestCommonPrefix.js: -------------------------------------------------------------------------------- 1 | // 转数组方式 2 | function longCommonPrefix(str1, str2){ 3 | let arr1 = str1.split('') 4 | let arr2 = str2.split('') 5 | if (arr1.length === 0 || arr2.length === 0){ 6 | return '' 7 | } 8 | let resultArr = [] 9 | let i = 0 10 | while(i !== arr1.length && i !== arr2.length){ 11 | if (arr1[i] === arr2[i]) { 12 | resultArr.push(arr1[i]) 13 | } else { 14 | return resultArr 15 | } 16 | i++ 17 | } 18 | return resultArr 19 | } 20 | 21 | // 非数组方式 22 | function longCommonPrefix2 (s1, s2) { 23 | if (s1 === '' || s2 === ''){ 24 | return '' 25 | } 26 | let i = 0 27 | while(i !== s1.length && i !== s2.length){ 28 | if (s1.substring(0, i) !== s2.substring(0, i)){ 29 | return s1.substring(0, i - 1) 30 | } 31 | i++; 32 | } 33 | } 34 | 35 | 36 | let s1 = 'hello' 37 | let s2 = 'he34' 38 | console.log(longCommonPrefix2(s1, s2)); -------------------------------------------------------------------------------- /排序/406.-medium-根据身高重建队列.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} people 3 | * @return {number[][]} 4 | */ 5 | var reconstructQueue = function (people) { 6 | if (!people.length) { 7 | return []; 8 | } 9 | // 先按身高升序 10 | people.sort((a, b) => { 11 | return a[0] - b[0]; 12 | }); 13 | 14 | // 再插入排序 15 | let index = 0; 16 | for(let i = 0; i < people.length; i++){ // 代表 17 | for(let j = index; j < people.length; j++){ 18 | if(index === people.length - 1) break; 19 | if(people[j][1] === i){ 20 | [people[index], people[j]] = [people[j], people[index]]; 21 | index++; 22 | } 23 | } 24 | } 25 | return people 26 | }; 27 | 28 | console.log(reconstructQueue([[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]])) -------------------------------------------------------------------------------- /数学类/1025-easy-除数博弈.js: -------------------------------------------------------------------------------- 1 | // 1025 easy 除数博弈 2 | 3 | // 爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。 4 | // 最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作: 5 | // 选出任一 x,满足 0 < x < N 且 N % x == 0 。 6 | // 用 N - x 替换黑板上的数字 N 。 7 | // 如果玩家无法执行这些操作,就会输掉游戏。 8 | // 只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。 9 | // 10 | // 11 | // 示例 1: 12 | // 输入:2 13 | // 输出:true 14 | // 解释:爱丽丝选择 1,鲍勃无法进行操作。 15 | 16 | // 示例 2: 17 | // 输入:3 18 | // 输出:false 19 | // 解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。 20 | //   21 | // 提示: 22 | // 1 <= N <= 1000 23 | 24 | 25 | /** 26 | * @param {number} N 27 | * @return {boolean} 28 | */ 29 | var divisorGame = function(N) { 30 | return N % 2 === 0 31 | }; -------------------------------------------------------------------------------- /数学类/1037-easy-有效的回旋镖.js: -------------------------------------------------------------------------------- 1 | // 1037. 有效的回旋镖 easy 2 | 3 | // 回旋镖定义为一组三个点,这些点各不相同且不在一条直线上。 4 | // 给出平面上三个点组成的列表,判断这些点是否可以构成回旋镖。 5 | // 6 | // 示例 1: 7 | // 输入:[[1,1],[2,3],[3,2]] 8 | // 输出:true 9 | 10 | // 示例 2: 11 | // 输入:[[1,1],[2,2],[3,3]] 12 | // 输出:false 13 | // 14 | // 提示: 15 | // points.length == 3 16 | // points[i].length == 2 17 | // 0 <= points[i][j] <= 100 18 | 19 | 20 | /** 21 | * @param {number[][]} points 22 | * @return {boolean} 23 | */ 24 | var isBoomerang = function(points) { 25 | let [a, b, c] = points; 26 | // 含有相同点 27 | if(a+'' === b+'' || a+'' === c+''|| b+'' === c+'')return false; 28 | // 三点垂直排列,斜率无法处理的情况 29 | if(a[0] === b[0] && a[0] === c[0] && b[0] === c[0]) return false; 30 | // 斜率不相同 31 | if(((b[1] - a[1]) / (b[0] - a[0])) !== ((c[1] - a[1]) / (c[0] - a[0]))){ 32 | return true 33 | }else{ 34 | return false; 35 | } 36 | }; 37 | 38 | console.log(isBoomerang([[1,1],[2,2],[3,3]])) -------------------------------------------------------------------------------- /数学类/1154-easy-一年中的第几天.js: -------------------------------------------------------------------------------- 1 | // 1154 easy 一年中的第几天 2 | 3 | // 给你一个按 YYYY-MM-DD 格式表示日期的字符串 date,请你计算并返回该日期是当年的第几天。 4 | // 通常情况下,我们认为 1 月 1 日是每年的第 1 天,1 月 2 日是每年的第 2 天,依此类推。 5 | // 每个月的天数与现行公元纪年法(格里高利历)一致。 6 | 7 | 8 | /** 9 | * @param {string} date 10 | * @return {number} 11 | */ 12 | var dayOfYear = function(date) { 13 | let dateArr = Array.of(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); 14 | let [year, month, day] = date.split('-').map(e=>parseInt(e)); 15 | let res = day; 16 | for(let i=0;i2 && ((year % 4==0 && year % 100 !=0) || year % 400 ==0)){ 20 | res += 1; 21 | } 22 | return res; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /数学类/1185-easy-一周中的第几天.js: -------------------------------------------------------------------------------- 1 | // 1185 easy 一周中的第几天 2 | 3 | // 给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。 4 | // 输入为三个整数:day、month 和 year,分别表示日、月、年。 5 | // 您返回的结果必须是这几个值中的一个 {"Sunday", "Monday", "Tuesday", "Wednesday", 6 | // "Thursday", "Friday", "Saturday"}。 7 | // 8 | // 9 | // 示例 1: 10 | // 输入:day = 31, month = 8, year = 2019 11 | // 输出:"Saturday" 12 | 13 | // 示例 2: 14 | // 输入:day = 18, month = 7, year = 1999 15 | // 输出:"Sunday" 16 | 17 | // 示例 3: 18 | // 输入:day = 15, month = 8, year = 1993 19 | // 输出:"Sunday" 20 | // 21 | // 提示: 22 | // 给出的日期一定是在 1971 到 2100 年之间的有效日期。 23 | 24 | 25 | /** 26 | * @param {number} day 27 | * @param {number} month 28 | * @param {number} year 29 | * @return {string} 30 | */ 31 | var dayOfTheWeek = function(day, month, year) { 32 | let d = new Date(`${year}-${month}-${day}`) 33 | let week = d.getDay() 34 | let arr = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] 35 | return arr[week] 36 | }; 37 | 38 | console.log(dayOfTheWeek('19', '9', '2019')) -------------------------------------------------------------------------------- /数学类/1227-medium-飞机座位分配概率.js: -------------------------------------------------------------------------------- 1 | // 1227 medium 飞机座位分配概率 2 | 3 | // 有 n 位乘客即将登机,飞机正好有 n 个座位。第一位乘客的票丢了,他随便选了一个座位坐下。 4 | // 5 | // 剩下的乘客将会: 6 | // 如果他们自己的座位还空着,就坐到自己的座位上, 7 | // 当他们自己的座位被占用时,随机选择其他座位 8 | // 第 n 位乘客坐在自己的座位上的概率是多少? 9 | // 10 | // 示例 1: 11 | // 输入:n = 1 12 | // 输出:1.00000 13 | // 解释:第一个人只会坐在自己的位置上。 14 | // 示例 2: 15 | // 输入: n = 2 16 | // 输出: 0.50000 17 | // 解释:在第一个人选好座位坐下后,第二个人坐在自己的座位上的概率是 0.5。 18 | //   19 | // 提示: 20 | // 1 <= n <= 10^5 21 | // 22 | 23 | 24 | /** 25 | * @param {number} n 26 | * @return {number} 27 | */ 28 | var nthPersonGetsNthSeat = function(n) { 29 | return n === 1? 1: 0.5 30 | }; -------------------------------------------------------------------------------- /数学类/1281-easu-整数的各位积和之差.js: -------------------------------------------------------------------------------- 1 | // 1281 easy 整数的各位积和之差 2 | 3 | // 给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 4 | // 5 | // 示例 1: 6 | // 输入:n = 234 7 | // 输出:15 8 | // 解释: 9 | // 各位数之积 = 2 * 3 * 4 = 24 10 | // 各位数之和 = 2 + 3 + 4 = 9 11 | // 结果 = 24 - 9 = 15 12 | // 示例 2: 13 | // 输入:n = 4421 14 | // 输出:21 15 | // 解释: 16 | // 各位数之积 = 4 * 4 * 2 * 1 = 32 17 | // 各位数之和 = 4 + 4 + 2 + 1 = 11 18 | // 结果 = 32 - 11 = 21 19 | // 20 | // 提示: 21 | // 1 <= n <= 10^5 22 | // 23 | 24 | /** 25 | * @param {number} n 26 | * @return {number} 27 | */ 28 | var subtractProductAndSum = function(n) { 29 | n = n + ''; 30 | let arr = n.split('') 31 | let ji = arr.reduce((p, n) => { 32 | return p * n; 33 | }) 34 | let sum = arr.reduce((p, n) => { 35 | return p/1 + n/1 36 | }) 37 | return ji - sum; 38 | }; -------------------------------------------------------------------------------- /数学类/1317-easy-将整数转换为两个无零整数的和.js: -------------------------------------------------------------------------------- 1 | // 1317 easy 将整数转换为两个无零整数的和 2 | 3 | //「无零整数」是十进制表示中 不含任何 0 的正整数。 4 | // 给你一个整数 n,请你返回一个 由两个整数组成的列表 [A, B],满足: 5 | // A 和 B 都是无零整数 6 | // A + B = n 7 | // 题目数据保证至少有一个有效的解决方案。 8 | // 如果存在多个有效解决方案,你可以返回其中任意一个。 9 | // 10 | // 示例 1: 11 | // 输入:n = 2 12 | // 输出:[1,1] 13 | // 解释:A = 1, B = 1. A + B = n 并且 A 和 B 的十进制表示形式都不包含任何 0 。 14 | // 示例 2: 15 | // 输入:n = 11 16 | // 输出:[2,9] 17 | // 示例 3: 18 | // 输入:n = 10000 19 | // 输出:[1,9999] 20 | // 示例 4: 21 | // 输入:n = 69 22 | // 输出:[1,68] 23 | // 示例 5: 24 | // 输入:n = 1010 25 | // 输出:[11,999] 26 | //   27 | // 28 | // 提示: 29 | // 2 <= n <= 10^4 30 | // 31 | /**1317 32 | * @param {number} n 33 | * @return {number[]} 34 | */ 35 | var getNoZeroIntegers = function(n) { 36 | for(let i = 1; i <= n / 2; i++){ 37 | let next = n - i; 38 | if (String(i).indexOf('0') === -1 && String(next).indexOf('0') === -1){ 39 | return [i, next] 40 | } 41 | } 42 | }; -------------------------------------------------------------------------------- /数学类/168-easy-excel列名称.js: -------------------------------------------------------------------------------- 1 | // 168 easy Excel列名称 2 | // 3 | // 给定一个正整数,返回它在 Excel 表中相对应的列名称。 4 | // 例如, 5 | // 1 -> A 6 | // 2 -> B 7 | // 3 -> C 8 | // ... 9 | // 26 -> Z 10 | // 27 -> AA 11 | // 28 -> AB 12 | // ... 13 | 14 | // 示例 1: 15 | // 输入: 1 16 | // 输出: "A" 17 | 18 | // 示例 2: 19 | // 输入: 28 20 | // 输出: "AB" 21 | 22 | // 示例 3: 23 | // 输入: 701 24 | // 输出: "ZY" 25 | 26 | /** 27 | * @param {number} n 28 | * @return {string} 29 | */ 30 | var convertToTitle = function(n) { 31 | let gewei = n % 26; 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /数学类/171-excel中的列序号.js: -------------------------------------------------------------------------------- 1 | // 给定一个Excel表格中的列名称,返回其相应的列序号。 2 | // 例如, 3 | // A -> 1 4 | // B -> 2 5 | // C -> 3 6 | // ... 7 | // Z -> 26 8 | // AA -> 27 9 | // AB -> 28 10 | // ... 11 | 12 | // 示例 1: 13 | // 输入: "A" 14 | // 输出: 1 15 | 16 | // 示例 2: 17 | // 输入: "AB" 18 | // 输出: 28 19 | 20 | // 示例 3: 21 | // 输入: "ZY" 22 | // 输出: 701 23 | 24 | 25 | /** 26 | * @param {string} s 27 | * @return {number} 28 | */ 29 | var titleToNumber = function(s) { 30 | let map = {}; 31 | let start = 'A'.charCodeAt() 32 | let end = 'Z'.charCodeAt() 33 | let count = 1 34 | for(let i = start; i <=end; i++){ 35 | map[String.fromCharCode(i)] = count; 36 | count++; 37 | } 38 | 39 | 40 | let arr = s.split(''); 41 | let sum = 0; 42 | let j = 0; 43 | for(let i = arr.length - 1; i >= 0; i--){ 44 | sum += map[arr[i]] * Math.pow(26, j); 45 | j++; 46 | } 47 | return sum; 48 | }; 49 | 50 | console.log(titleToNumber("AB")) -------------------------------------------------------------------------------- /数学类/172-easy-阶乘后的零.js: -------------------------------------------------------------------------------- 1 | // 172. 阶乘后的零 easy 2 | 3 | // 给定一个整数 n,返回 n! 结果尾数中零的数量。 4 | // 5 | // 示例 1: 6 | // 输入: 3 7 | // 输出: 0 8 | // 解释: 3! = 6, 尾数中没有零。 9 | 10 | // 示例 2: 11 | // 输入: 5 12 | // 输出: 1 13 | // 解释: 5! = 120, 尾数中有 1 个零. 14 | // 说明: 你算法的时间复杂度应为 O(log n) 。 15 | 16 | 17 | /** 18 | * @param {number} n 19 | * @return {number} 20 | */ 21 | var trailingZeroes = function(n) { 22 | if(n<5)return 0; 23 | let fiveCount = 0 24 | while(n >= 5){ 25 | fiveCount += ~~(n / 5); 26 | n = n / 5; 27 | } 28 | return fiveCount 29 | }; 30 | console.log(trailingZeroes(25)) -------------------------------------------------------------------------------- /数学类/231-easy-2的幂.js: -------------------------------------------------------------------------------- 1 | // 231 easy 2的幂 2 | 3 | // 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 4 | // 5 | // 示例 1: 6 | // 输入: 1 7 | // 输出: true 8 | // 解释: 20 = 1 9 | 10 | // 示例 2: 11 | // 输入: 16 12 | // 输出: true 13 | // 解释: 24 = 16 14 | 15 | // 示例 3: 16 | // 输入: 218 17 | // 输出: false 18 | 19 | 20 | /** 21 | * @param {number} n 22 | * @return {boolean} 23 | */ 24 | var isPowerOfTwo = function(n) { 25 | if (n === 0) return false; 26 | if(n ===1) return true; 27 | let index = 0 28 | while(true){ 29 | if (n === 2) return true; 30 | n = n / 2 31 | if (n % 2 !== 0){ 32 | return false 33 | } 34 | index++; 35 | } 36 | }; -------------------------------------------------------------------------------- /数学类/258-easy-各位相加.js: -------------------------------------------------------------------------------- 1 | // 258 easy 各位相加 2 | 3 | // 给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。 4 | // 5 | // 示例: 6 | // 输入: 38 7 | // 输出: 2 8 | // 解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。 9 | 10 | // 进阶: 11 | // 你可以不使用循环或者递归,且在 O(1) 时间复杂度内解决这个问题吗? 12 | 13 | /** 14 | * @param {number} num 15 | * @return {number} 16 | */ 17 | var addDigits = function(num) { 18 | let arr = (num + '').split('') 19 | if (arr.length === 1) return num; 20 | 21 | let sum = 0 22 | for(let i = 0; i < arr.length; i++){ 23 | sum += Number(arr[i]) 24 | } 25 | return addDigits(sum) 26 | }; 27 | 28 | console.log(addDigits(38)) -------------------------------------------------------------------------------- /数学类/263-easy-丑数.js: -------------------------------------------------------------------------------- 1 | // 263 easy 丑数 2 | 3 | // 编写一个程序判断给定的数是否为丑数。 4 | // 丑数就是只包含质因数 2, 3, 5 的正整数。 5 | // 6 | // 示例 1: 7 | // 输入: 6 8 | // 输出: true 9 | // 解释: 6 = 2 × 3 10 | 11 | // 示例 2: 12 | // 输入: 8 13 | // 输出: true 14 | // 解释: 8 = 2 × 2 × 2 15 | 16 | // 示例 3: 17 | // 输入: 14 18 | // 输出: false 19 | // 解释: 14 不是丑数,因为它包含了另外一个质因数 7。 20 | 21 | // 说明: 22 | // 1 是丑数。 23 | // 输入不会超过 32 位有符号整数的范围: [−231,  231 − 1]。 24 | 25 | 26 | /** 27 | * @param {number} num 28 | * @return {boolean} 29 | */ 30 | var isUgly = function(num) { 31 | if(num === 0) return false; 32 | if(num === 1)return true; 33 | while(true){ 34 | if(num === 1) return true; 35 | if(num % 2 !== 0 && num % 3 !== 0 && num %5 !== 0){ 36 | return false; 37 | } 38 | if(num % 2 === 0){ 39 | num = num / 2 40 | } 41 | if(num % 3 === 0){ 42 | num /= 3; 43 | } 44 | if(num % 5 === 0){ 45 | num /= 5; 46 | } 47 | } 48 | }; 49 | 50 | console.log(isUgly(4)) -------------------------------------------------------------------------------- /数学类/279-完全平方数.js: -------------------------------------------------------------------------------- 1 | // 279 medium 完全平方数 2 | 3 | // 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 4 | // 5 | // 示例 1: 6 | // 输入: n = 12 7 | // 输出: 3 8 | // 解释: 12 = 4 + 4 + 4. 9 | 10 | // 示例 2: 11 | // 输入: n = 13 12 | // 输出: 2 13 | // 解释: 13 = 4 + 9. 14 | 15 | /** 16 | * @param {number} n 17 | * @return {number} 18 | */ 19 | var numSquares = function(n) { 20 | 21 | }; -------------------------------------------------------------------------------- /数学类/292-easy-nim游戏.js: -------------------------------------------------------------------------------- 1 | // 292 easy nim游戏 2 | 3 | // 你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 4 | // 拿掉最后一块石头的人就是获胜者。你作为先手。 5 | // 你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。 6 | // 7 | // 示例: 8 | // 输入: 4 9 | // 输出: false 10 | // 解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛; 11 | //   因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。 12 | 13 | 14 | 15 | /** 16 | * @param {number} n 17 | * @return {boolean} 18 | */ 19 | var canWinNim = function(n) { 20 | return n % 4 !== 0 21 | }; -------------------------------------------------------------------------------- /数学类/326-easy-3的幂.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * @param {number} n 5 | * @return {boolean} 6 | */ 7 | var isPowerOfThree = function(n) { 8 | if (n === 0) return false; 9 | if(n ===1) return true; 10 | let index = 0 11 | while(true){ 12 | if (n === 3) return true; 13 | n = n / 3 14 | if (n % 3 !== 0){ 15 | return false 16 | } 17 | index++; 18 | } 19 | }; 20 | 21 | console.log(isPowerOfThree(1)) -------------------------------------------------------------------------------- /数学类/453-easy-最小移动次数使数组元素相等.js: -------------------------------------------------------------------------------- 1 | // 453 easy 2 | 3 | // 给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。 4 | // 每次移动可以使 n - 1 个元素增加 1。 5 | // 6 | // 示例: 7 | // 输入: 8 | // [1,2,3] 9 | // 输出: 10 | // 3 11 | // 12 | // 解释: 13 | // 只需要3次移动(注意每次移动会增加两个元素的值): 14 | // [1,2,3] => [2,3,3] => [3,4,3] => [4,4,4] 15 | 16 | /** 17 | * @param {number[]} nums 18 | * @return {number} 19 | */ 20 | var minMoves = function(nums) { 21 | if (new Set(nums).size === 1) return 0; 22 | let min = Number.MAX_SAFE_INTEGER, sum = 0; 23 | for(let i = 0; i < nums.length; i++){ 24 | sum += nums[i]; 25 | if (nums[i] < min) min = nums[i]; 26 | } 27 | return sum - min * (nums.length) 28 | }; 29 | 30 | console.log(minMoves([-24797638,490027,33368690,-47479941,-5102237,17513926,15180540,-9616574,-45910828,-46544264])) 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /数学类/507-easy-完美数.js: -------------------------------------------------------------------------------- 1 | // 507 easy 完美数 2 | 3 | // 对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为“完美数”。 4 | // 给定一个 整数 n, 如果他是完美数,返回 True,否则返回 False 5 | // 6 | // 示例: 7 | // 输入: 28 8 | // 输出: True 9 | // 解释: 28 = 1 + 2 + 4 + 7 + 14 10 | // 11 | // 提示: 12 | // 输入的数字 n 不会超过 100,000,000. (1e8) 13 | 14 | 15 | /** 16 | * @param {number} num 17 | * @return {boolean} 18 | */ 19 | var checkPerfectNumber = function(num) { 20 | if(num <= 2) return false 21 | let arr = [1] 22 | 23 | let index = ~~(num/2) 24 | while(index !== 1){ 25 | if(num % index === 0){ 26 | arr.push(index); 27 | } 28 | index--; 29 | } 30 | let sum = arr.reduce((p,n) => { 31 | return p+n; 32 | }, 0) 33 | return sum === num; 34 | }; 35 | 36 | console.log(checkPerfectNumber(28)) -------------------------------------------------------------------------------- /数学类/5452-easy-判断能否形成等差数列.js: -------------------------------------------------------------------------------- 1 | 2 | //5452. 判断能否形成等差数列 easy 3 | 4 | // 给你一个数字数组 arr 。 5 | // 如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列 。 6 | // 如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false 。 7 | // 8 | //   9 | // 示例 1: 10 | // 输入:arr = [3,5,1] 11 | // 输出:true 12 | // 解释:对数组重新排序得到 [1,3,5] 或者 [5,3,1] ,任意相邻两项的差分别为 2 或 -2 ,可以形成等差数列。 13 | // 示例 2: 14 | // 输入:arr = [1,2,4] 15 | // 输出:false 16 | // 解释:无法通过重新排序得到等差数列。 17 | //   18 | // 提示: 19 | // 2 <= arr.length <= 1000 20 | // -10^6 <= arr[i] <= 10^6 21 | 22 | 23 | /** 24 | * @param {number[]} arr 25 | * @return {boolean} 26 | */ 27 | var canMakeArithmeticProgression = function(arr) { 28 | arr.sort((a,b)=>{return a-b}); 29 | let dif = arr[1] - arr[0] 30 | for(let i= 2;i { 24 | return b - a; 25 | }); 26 | for(let i = 0; i < arr.length; i++){ 27 | if (arr[i] !== sortedArr[i]){ 28 | let index = arr.lastIndexOf(sortedArr[i]); 29 | [arr[i], arr[index]] = [arr[index], arr[i]] 30 | break; 31 | } 32 | } 33 | return arr.join('') / 1; 34 | }; 35 | 36 | console.log(maximumSwap(1993)) -------------------------------------------------------------------------------- /数学类/69-easy-x的平方根.js: -------------------------------------------------------------------------------- 1 | // 69 easy 平方根 2 | 3 | // 实现 int sqrt(int x) 函数。 4 | // 计算并返回 x 的平方根,其中 x 是非负整数。 5 | // 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 6 | // 7 | // 示例 1: 8 | // 输入: 4 9 | // 输出: 2 10 | 11 | // 示例 2: 12 | // 输入: 8 13 | // 输出: 2 14 | 15 | // 说明: 8 的平方根是 2.82842..., 16 | // 由于返回类型是整数,小数部分将被舍去。 17 | 18 | 19 | /** 20 | * @param {number} x 21 | * @return {number} 22 | */ 23 | var mySqrt = function(x) { 24 | if (x === 0) return 0; 25 | if (x === 1) return 1; 26 | for(let i = 1; i <= Math.floor(x / 2); i++){ 27 | if ( i * i <= x && (i+1) * (i+1) > x){ 28 | return i; 29 | } 30 | } 31 | }; 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /数学类/728-easy-自除数.js: -------------------------------------------------------------------------------- 1 | // 728 easy 自除数 2 | 3 | // 自除数 是指可以被它包含的每一位数除尽的数。 4 | // 例如,128 是一个自除数,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。 5 | // 还有,自除数不允许包含 0 。 6 | // 给定上边界和下边界数字,输出一个列表,列表的元素是边界(含边界)内所有的自除数。 7 | // 8 | // 示例 1: 9 | // 输入: 10 | // 上边界left = 1, 下边界right = 22 11 | // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22] 12 | 13 | // 注意: 14 | // 每个输入参数的边界满足 1 <= left <= right <= 10000。 15 | 16 | 17 | /** 18 | * @param {number} left 19 | * @param {number} right 20 | * @return {number[]} 21 | */ 22 | var selfDividingNumbers = function(left, right) { 23 | let arr = [] 24 | for(let i = left; i <= right; i++){ 25 | if (isZichushu(i)) { 26 | arr.push(i) 27 | } 28 | } 29 | return arr; 30 | }; 31 | 32 | function isZichushu(n) { 33 | let arr = (n + '').split('') 34 | if (arr.indexOf('0') >= 0){ 35 | return false; 36 | } 37 | for(let i = 0; i < arr.length; i++){ 38 | if (n % arr[i] !== 0) return false; 39 | } 40 | return true; 41 | } -------------------------------------------------------------------------------- /数学类/8-medium-字符串转换整数.js: -------------------------------------------------------------------------------- 1 | 2 | //8. 字符串转换整数 (atoi) medium 3 | /** 4 | * @param {string} str 5 | * @return {number} 6 | */ 7 | var myAtoi = function(str) { 8 | let s = str.trim(); 9 | 10 | if(s[0] === '+' || s[0] === '-'){ 11 | if(s.length === 1)return 0; 12 | }else{ 13 | if(/[^0-9]/.test(s[0])){ 14 | return 0; 15 | } 16 | } 17 | let a = parseInt(s); 18 | if (a > Math.pow(2, 31) - 1) return Math.pow(2, 31) - 1; 19 | if (a < Math.pow(-2, 31)) return Math.pow(-2, 31); 20 | return isNaN(a) ? 0: a; 21 | }; 22 | 23 | console.log(myAtoi(" -42")) 24 | -------------------------------------------------------------------------------- /数学类/877-medium-石子游戏.js: -------------------------------------------------------------------------------- 1 | // 877 medium 石子游戏 2 | 3 | // 亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。 4 | // 游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。 5 | // 亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 6 | // 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。 7 | // 假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。 8 | // 9 | // 10 | // 示例: 11 | // 输入:[5,3,4,5] 12 | // 输出:true 13 | // 解释: 14 | // 亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。 15 | // 假设他取了前 5 颗,这一行就变成了 [3,4,5] 。 16 | // 如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。 17 | // 如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。 18 | // 这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。 19 | 20 | 21 | /** 22 | * 先手必为赢家 23 | * @param {number[]} piles 24 | * @return {boolean} 25 | */ 26 | var stoneGame = function(piles) { 27 | return true 28 | }; -------------------------------------------------------------------------------- /数学类/9-easy-回文数.js: -------------------------------------------------------------------------------- 1 | // easy 9 回文数 2 | 3 | // 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 4 | // 5 | // 示例 1: 6 | // 输入: 121 7 | // 输出: true 8 | 9 | // 示例 2: 10 | // 输入: -121 11 | // 输出: false 12 | // 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 13 | 14 | // 示例 3: 15 | // 输入: 10 16 | // 输出: false 17 | // 解释: 从右向左读, 为 01 。因此它不是一个回文数。 18 | 19 | // 进阶: 20 | // 你能不将整数转为字符串来解决这个问题吗? 21 | 22 | /** 23 | * @param {number} x 24 | * @return {boolean} 25 | */ 26 | var isPalindrome = function(x) { 27 | let arr = (x + '').split('') 28 | let prev = 0; 29 | let next = arr.length - 1; 30 | while(true){ 31 | // 退出条件 32 | if (next - prev === 0 || next - prev === -1) { 33 | return true; 34 | } 35 | if (arr[prev] !== arr[next]){ 36 | return false; 37 | } 38 | prev++; 39 | next--; 40 | } 41 | }; -------------------------------------------------------------------------------- /数学类/976-easy-三角形最大周长.js: -------------------------------------------------------------------------------- 1 | // easy 976 三角形最大周长 2 | 3 | // 给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。 4 | // 如果不能形成任何面积不为零的三角形,返回 0。 5 | // 6 | // 示例 1: 7 | // 输入:[2,1,2] 8 | // 输出:5 9 | 10 | // 示例 2: 11 | // 输入:[1,2,1] 12 | // 输出:0 13 | 14 | // 示例 3: 15 | // 输入:[3,2,3,4] 16 | // 输出:10 17 | 18 | // 示例 4: 19 | // 输入:[3,6,2,3] 20 | // 输出:8 21 | // 22 | // 提示: 23 | // 3 <= A.length <= 10000 24 | // 1 <= A[i] <= 10^6 25 | 26 | /** 27 | * @param {number[]} A 28 | * @return {number} 29 | */ 30 | var largestPerimeter = function(A) { 31 | A.sort((a, b) => { 32 | return b - a 33 | }) 34 | for(let i = 0; i < A.length - 2; i++){ 35 | if (A[i + 1] + A[i + 2] > A[i]){ 36 | return A[i] + A[i + 1] + A[i + 2] 37 | } 38 | } 39 | return 0 40 | }; -------------------------------------------------------------------------------- /数学类/lcp2-easy-分式化简.js: -------------------------------------------------------------------------------- 1 | // lcp2 easy 分式化简 2 | 3 | //示例 1: 4 | // 输入:cont = [3, 2, 0, 2] 5 | // 输出:[13, 4] 6 | // 解释:原连分数等价于3 + (1 / (2 + (1 / (0 + 1 / 2))))。注意[26, 8], [-13, -4]都不是正确答案。 7 | // 8 | 9 | /** 10 | * @param {number[]} cont 11 | * @return {number[]} 12 | */ 13 | var fraction = function(cont) { 14 | if (!cont.length)return 0; 15 | if (cont.length === 1)return [cont[0],1]; 16 | let fenzi = 1; 17 | let fenmu = cont[cont.length - 1]; 18 | for (let i = cont.length - 2; i >= 0; i--) { 19 | fenzi = cont[i] * fenmu + fenzi; 20 | [fenzi, fenmu] = [fenmu, fenzi] 21 | } 22 | // 最后一次,其实不用再取倒数了,但是上面循环取倒数了,所以下面再倒一次 23 | return [fenmu, fenzi] 24 | }; 25 | console.log(fraction([1, 5, 6, 6, 5, 7, 5, 5, 4, 7])) -------------------------------------------------------------------------------- /数组类/1512-easy-好数对的数目.js: -------------------------------------------------------------------------------- 1 | 2 | //1512. 好数对的数目 easy 3 | 4 | // 给你一个整数数组 nums 。 5 | // 如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。 6 | // 返回好数对的数目。 7 | // 8 | // 9 | // 示例 1: 10 | // 输入:nums = [1,2,3,1,1,3] 11 | // 输出:4 12 | // 解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始 13 | // 示例 2: 14 | // 输入:nums = [1,1,1,1] 15 | // 输出:6 16 | // 解释:数组中的每组数字都是好数对 17 | // 示例 3: 18 | // 输入:nums = [1,2,3] 19 | // 输出:0 20 | //   21 | // 22 | // 提示: 23 | // 1 <= nums.length <= 100 24 | // 1 <= nums[i] <= 100 25 | 26 | 27 | var numIdenticalPairs = function(nums) { 28 | if (nums.length === 1) return 0; 29 | let cnt = 0; 30 | for(let i = 0; i < nums.length; i++){ 31 | for(let j = 0; j < nums.length; j++){ 32 | if (i < j && nums[i] === nums[j]){ 33 | cnt++; 34 | } 35 | } 36 | } 37 | return cnt; 38 | }; -------------------------------------------------------------------------------- /数组类/605-flower.js: -------------------------------------------------------------------------------- 1 | 2 | // 种花问题 3 | // 描述:相邻地块不能种 4 | // 建模: [1,0,0,0,1] 1表示种花了,0表示没有 5 | // 输入1,返回true。因为可以在中间种[1,0,1,0,1] 6 | 7 | /** 8 | * 可以返回true,不可以返回false 9 | * @param arr 目前花坛种花与不种花的数据结构表示 10 | * @param n 让你再在花坛种n块花 11 | */ 12 | function fn (arr, n) { 13 | let start0Count = arr.indexOf(1) 14 | let end0Count = arr.length - arr.lastIndexOf(1) - 1 15 | let indexOf1 = [] 16 | for (let i = arr.indexOf(1); i <= arr.lastIndexOf(1); i++) { 17 | if (arr[i] === 1){ 18 | indexOf1.push(i) 19 | } 20 | } 21 | let pace = [] 22 | for (let i = 1; i < indexOf1.length; i++) { 23 | pace.push(indexOf1[i] - indexOf1[i - 1] -1) 24 | } 25 | // 计算中间能种多少,两边能种多少,加起来就是总共能多少 26 | let interTotal = 0 27 | for (let i = 0; i < pace.length; i++) { 28 | interTotal+= Math.floor((pace[i] - 1) / 2) 29 | } 30 | let borderTotal = Math.floor(start0Count / 2 ) + Math.floor(end0Count / 2 ) 31 | return interTotal + borderTotal >= n 32 | } 33 | 34 | let arr = [1,0,0,0,0,0,1] 35 | console.log(fn(arr, 2)); -------------------------------------------------------------------------------- /数组类/sortedArr/154-hard-寻找旋转排序数组中的最小值 II .js: -------------------------------------------------------------------------------- 1 | // 154 hard 寻找旋转排序数组中的最小值 II 2 | 3 | // 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 4 | // ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 5 | // 请找出其中最小的元素。 6 | // 注意数组中可能存在重复的元素。 7 | // 8 | // 示例 1: 9 | // 输入: [1,3,5] 10 | // 输出: 1 11 | // 示例 2: 12 | // 输入: [2,2,2,0,1] 13 | // 输出: 0 14 | // 说明: 15 | // 这道题是 寻找旋转排序数组中的最小值 的延伸题目。 16 | // 允许重复会影响算法的时间复杂度吗?会如何影响,为什么? 17 | 18 | 19 | /** 20 | * @param {number[]} nums 21 | * @return {number} 22 | */ 23 | var findMin = function(nums) { 24 | return Math.min(...nums) 25 | }; -------------------------------------------------------------------------------- /数组类/sortedArr/26-delSortedArrDupItem.js: -------------------------------------------------------------------------------- 1 | //leetcode-27-easy 2 | // topic:删除排序数组中的重复项,返回删除后数组的长度 3 | 4 | // 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 5 | // 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 6 | // 7 | // 示例 1: 8 | // 给定数组 nums = [1,1,2], 9 | // 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 10 | // 你不需要考虑数组中超出新长度后面的元素。 11 | // 12 | // 示例 2: 13 | // 给定 nums = [0,0,1,1,1,2,2,3,3,4], 14 | // 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 15 | // 你不需要考虑数组中超出新长度后面的元素。 16 | // 17 | // 说明: 18 | // 为什么返回数值是整数,但输出的答案是数组呢? 19 | // 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 20 | // 你可以想象内部操作如下: 21 | 22 | 23 | function deDupSortedArr(arr){ 24 | for (let i = arr.length - 1; i > 0; i--) { 25 | if (arr[i] === arr[i - 1]){ 26 | arr.splice(i, 1) 27 | } 28 | } 29 | return arr.length; 30 | } 31 | 32 | console.log(deDupSortedArr([1,1,2])); 33 | console.log(deDupSortedArr([0,0,1,1,1,2,2,3,3,4])); -------------------------------------------------------------------------------- /数组类/sortedArr/34-medium-在排序数组中查找元素的第一个和最后一个位置.js: -------------------------------------------------------------------------------- 1 | // 34. medium 在排序数组中查找元素的第一个和最后一个位置 2 | 3 | // 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 4 | // 你的算法时间复杂度必须是 O(log n) 级别。 5 | // 如果数组中不存在目标值,返回 [-1, -1]。 6 | // 7 | // 示例 1: 8 | // 输入: nums = [5,7,7,8,8,10], target = 8 9 | // 输出: [3,4] 10 | // 示例 2: 11 | // 输入: nums = [5,7,7,8,8,10], target = 6 12 | // 输出: [-1,-1] 13 | 14 | 15 | 16 | /** 17 | * @param {number[]} nums 18 | * @param {number} target 19 | * @return {number[]} 20 | */ 21 | var searchRange = function(nums, target) { 22 | if(!nums.length)return [-1,-1] 23 | if(nums.indexOf(target) === -1)return [-1,-1] 24 | return [nums.indexOf(target), nums.lastIndexOf(target)] 25 | }; -------------------------------------------------------------------------------- /数组类/sortedArr/35-searchInsertPos.js: -------------------------------------------------------------------------------- 1 | // LeetCode-35-easy 2 | // 3 | // 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 4 | // 你可以假设数组中无重复元素。 5 | // 6 | // 示例 1: 7 | // 输入: [1,3,5,6], 5 8 | // 输出: 2 9 | // 10 | // 示例 2: 11 | // 输入: [1,3,5,6], 2 12 | // 输出: 1 13 | // 14 | // 示例 3: 15 | // 输入: [1,3,5,6], 7 16 | // 输出: 4 17 | // 18 | // 示例 4: 19 | // 输入: [1,3,5,6], 0 20 | // 输出: 0 21 | 22 | function searchInertPos(arr, target){ 23 | // 数组中有target的情况 24 | let index = arr.indexOf(target) 25 | if (index !== -1) { 26 | return index 27 | } 28 | 29 | // 数组中没有target的情况 30 | if (arr[0] > target) return 0 31 | if (arr[arr.length - 1] < target) return arr.length 32 | for (let i = 0; i < arr.length - 1; i++) { 33 | if (target > arr[i] && target < arr[i + 1]){ 34 | return i + 1 35 | } 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /数组类/sortedArr/977-squareSortedArr.js: -------------------------------------------------------------------------------- 1 | // leetcode-977-easy 2 | 3 | // 给定一个按非递减顺序排序的整数数组A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。 4 | // 5 | // 示例 1: 6 | // 输入:[-4,-1,0,3,10] 7 | // 输出:[0,1,9,16,100] 8 | // 9 | // 示例 2: 10 | // 输入:[-7,-3,2,3,11] 11 | // 输出:[4,9,9,49,121] 12 | // 13 | // 提示: 14 | // 1. 1 <= A.length <= 10000 15 | // 2. -10000 <= A[i] <= 10000 16 | // 3. A 已按非递减顺序排序。 17 | 18 | function square(arr) { 19 | let resultArr = arr.map((val) => { 20 | return val * val; 21 | }) 22 | return resultArr.sort((a, b) => { 23 | return a - b 24 | }) 25 | } 26 | 27 | // console.log(square([-4,-1,0,3,10])) 28 | console.log(square([-7,-3,2,3,11])) 29 | -------------------------------------------------------------------------------- /数组类/unSortedArr/1-easy-两数之和.js: -------------------------------------------------------------------------------- 1 | // easy 1 两数之和 2 | // 3 | // 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 4 | // 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 5 | // 6 | // 示例: 7 | // 给定 nums = [2, 7, 11, 15], target = 9 8 | // 因为 nums[0] + nums[1] = 2 + 7 = 9 9 | // 所以返回 [0, 1] 10 | 11 | 12 | /** 13 | * @param {number[]} nums 14 | * @param {number} target 15 | * @return {number[]} 返回两个数的下标 16 | */ 17 | var twoSum = function(nums, target) { 18 | if (nums.length === 1) return [] 19 | 20 | let hash = {} 21 | for(let i = 0; i < nums.length; i++){ 22 | if(!hash[nums[i]]) hash[nums[i]] = i; 23 | } 24 | for(let i = 0; i < nums.length; i++){ 25 | if (hash[target - nums[i]] >= 0 && hash[target - nums[i]] !== i){ 26 | return [i, hash[target - nums[i]]]; 27 | } 28 | } 29 | }; 30 | 31 | console.log(twoSum([2, 7, 11, 15], 9)) -------------------------------------------------------------------------------- /数组类/unSortedArr/1014-medium-最佳观光组合.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 暴力,超时 5 | * @param {number[]} A 6 | * @return {number} 7 | */ 8 | var maxScoreSightseeingPair = function(A) { 9 | let max = Number.MIN_SAFE_INTEGER 10 | for(let i = 0; i < A.length; i++){ 11 | for(let j = 0; j < A.length; j++){ 12 | if(i !== j){ 13 | if(A[i] + A[j] - Math.abs(i - j) > max){ 14 | max = A[i] + A[j] - Math.abs(i - j) 15 | } 16 | } 17 | } 18 | } 19 | return max; 20 | }; 21 | 22 | 23 | 24 | /** 25 | * 26 | * @param {number[]} A 27 | * @return {number} 28 | */ 29 | var maxScoreSightseeingPair2 = function(A) { 30 | if(!A.length) return 0; 31 | 32 | let res = 0 // A[0] - 0; 33 | let preMax = A[0]; // A[0] + 0; 34 | for(let i = 1; i < A.length; i++){ 35 | res = Math.max(res, preMax + A[i] - i); 36 | preMax = Math.max(preMax, A[i] + i); 37 | } 38 | return res; 39 | }; 40 | 41 | console.log(maxScoreSightseeingPair2([8,1,5,2,6])) -------------------------------------------------------------------------------- /数组类/unSortedArr/1051-heightCheck.js: -------------------------------------------------------------------------------- 1 | // 学校在拍年度纪念照时,一般要求学生按照 非递减 的高度顺序排列。 2 | // 3 | // 请你返回至少有多少个学生没有站在正确位置数量。该人数指的是:能让所有学生以 非递减 高度排列的必要移动人数。 4 | // 5 | // 示例: 6 | // 输入:[1,1,4,2,1,3] 7 | // 输出:3 8 | // 解释: 9 | // 高度为 4、3 和最后一个 1 的学生,没有站在正确的位置。 10 | //   11 | // 12 | // 提示: 13 | // 1 <= heights.length <= 100 14 | // 1 <= heights[i] <= 100 15 | 16 | // 主要是理解题意: 排序后比较和原数组有多少不一样 17 | 18 | function howMany(arr){ 19 | let old = [...arr] 20 | let newArr = arr.sort((a, b)=>{return a-b}) 21 | let howMany = 0 22 | for (let i = 0; i < newArr.length; i++) { 23 | if (old[i] !== newArr[i]){ 24 | howMany++ 25 | } 26 | } 27 | return howMany 28 | } 29 | 30 | console.log(howMany([1,1,4,2,1,3])) 31 | -------------------------------------------------------------------------------- /数组类/unSortedArr/1089-easy-复写0.js: -------------------------------------------------------------------------------- 1 | // 1089 easy 复写0 2 | 3 | // 给你一个长度固定的整数数组 数组类,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。 4 | // 注意:请不要在超过该数组长度的位置写入元素。 5 | // 要求:请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。 6 | // 7 | // 8 | // 示例 1: 9 | // 输入:[1,0,2,3,0,4,5,0] 10 | // 输出:null 11 | // 解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4] 12 | 13 | // 示例 2: 14 | // 输入:[1,2,3] 15 | // 输出:null 16 | // 解释:调用函数后,输入的数组将被修改为:[1,2,3] 17 | 18 | /** 19 | * @param {number[]} arr 20 | * @return {void} Do not return anything, modify 数组类 in-place instead. 21 | */ 22 | var duplicateZeros = function(arr) { 23 | for(let i = arr.length - 1; i >= 0; i--){ 24 | if (arr[i] === 0){ 25 | overWrite(arr, i) 26 | } 27 | } 28 | }; 29 | 30 | /** 31 | * 实现一个 数组复写方法 32 | * @param arr 要复写的数组 33 | * @param index 被复写元素的位置 34 | */ 35 | function overWrite(arr, index){ 36 | for(let i = arr.length - 1; i > index; i--){ 37 | arr[i] = arr[i - 1] 38 | } 39 | } 40 | 41 | let a = [1,0,2,3,0,4,5,0] 42 | duplicateZeros(a) 43 | console.log(a) -------------------------------------------------------------------------------- /数组类/unSortedArr/1217-easy-玩筹码.js: -------------------------------------------------------------------------------- 1 | // 1217. 玩筹码 easy 2 | 3 | // 数轴上放置了一些筹码,每个筹码的位置存在数组 chips 当中。 4 | // 你可以对 任何筹码 执行下面两种操作之一(不限操作次数,0 次也可以): 5 | // 将第 i 个筹码向左或者右移动 2 个单位,代价为 0。 6 | // 将第 i 个筹码向左或者右移动 1 个单位,代价为 1。 7 | // 最开始的时候,同一位置上也可能放着两个或者更多的筹码。 8 | // 返回将所有筹码移动到同一位置(任意位置)上所需要的最小代价。 9 | // 10 | // 示例 1: 11 | // 输入:chips = [1,2,3] 12 | // 输出:1 13 | // 解释:第二个筹码移动到位置三的代价是 1,第一个筹码移动到位置三的代价是 0,总代价为 1。 14 | // 示例 2: 15 | // 输入:chips = [2,2,2,3,3] 16 | // 输出:2 17 | // 解释:第四和第五个筹码移动到位置二的代价都是 1,所以最小总代价为 2。 18 | // 19 | // 提示: 20 | // 1 <= chips.length <= 100 21 | // 1 <= chips[i] <= 10^9 22 | 23 | var minCostToMoveChips = function(chips) { 24 | let minCost = Number.MAX_SAFE_INTEGER 25 | for(let i = 0; i < chips.length; i++){ 26 | let cost = 0; 27 | for(let j = 0; j < chips.length; j++){ 28 | if(i !== j && Math.abs(chips[i] - chips[j]) % 2 !== 0){ 29 | cost += 1; 30 | } 31 | } 32 | minCost = Math.min(minCost, cost) 33 | } 34 | return minCost; 35 | }; 36 | -------------------------------------------------------------------------------- /数组类/unSortedArr/1232-easy-缀点成线.js: -------------------------------------------------------------------------------- 1 | // 1232 easy 缀点成线 2 | 3 | //在一个 XY 坐标系中有一些点,我们用数组 coordinates 来分别记录它们的坐标, 4 | // 其中 coordinates[i] = [x, y] 表示横坐标为 x、纵坐标为 y 的点。 5 | // 6 | // 请你来判断,这些点是否在该坐标系中属于同一条直线上 7 | // 8 | 9 | /** 10 | * @param {number[][]} coordinates 11 | * @return {boolean} 12 | */ 13 | var checkStraightLine = function(coordinates) { 14 | if(!coordinates)return true; 15 | if(coordinates.length <= 2) return true; 16 | 17 | let xie = xielv(coordinates[0], coordinates[1]); 18 | for(let i = 1; i < coordinates.length - 1; i++){ 19 | if(xielv(coordinates[i], coordinates[i+1]) !== xie){ 20 | return false; 21 | } 22 | } 23 | return true; 24 | }; 25 | 26 | var xielv = (p1, p2) => { 27 | if(p1[0] === p2[0])return 1; // 两个垂直的点 28 | return (p1[1] - p2[1]) / (p1[0] - p2[0]) 29 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/1248-medium-统计「优美子数组」.js: -------------------------------------------------------------------------------- 1 | //1248. 统计「优美子数组」medium 2 | 3 | 4 | 5 | // 暴力:会超时 6 | var numberOfSubarrays = function(nums, k) { 7 | let cnt = 0; 8 | for(let i = 0; i <= nums.length - k; i++){ 9 | let c = 0; 10 | let idx = i; 11 | while(c <= k && idx < nums.length){ 12 | if(nums[idx] % 2 === 1){ 13 | c++; 14 | } 15 | if(c === k){cnt++;} 16 | idx++; 17 | } 18 | } 19 | return cnt; 20 | }; 21 | 22 | 23 | var numberOfSubarrays2 = function(nums, k) { 24 | let cnt = 0; 25 | 26 | return cnt; 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /数组类/unSortedArr/1295-easy-统计位数为偶数的数字.js: -------------------------------------------------------------------------------- 1 | // 1295. 统计位数为偶数的数字 easy 2 | 3 | //给你一个整数数组 nums,请你返回其中位数为 偶数 的数字的个数。 4 | // 5 | // 示例 1: 6 | // 输入:nums = [12,345,2,6,7896] 7 | // 输出:2 8 | // 解释: 9 | // 12 是 2 位数字(位数为偶数)  10 | // 345 是 3 位数字(位数为奇数)   11 | // 2 是 1 位数字(位数为奇数)  12 | // 6 是 1 位数字 位数为奇数)  13 | // 7896 是 4 位数字(位数为偶数)   14 | // 因此只有 12 和 7896 是位数为偶数的数字 15 | // 示例 2: 16 | // 输入:nums = [555,901,482,1771] 17 | // 输出:1 18 | // 解释: 19 | // 只有 1771 是位数为偶数的数字。 20 | //   21 | // 22 | // 提示: 23 | // 1 <= nums.length <= 500 24 | // 1 <= nums[i] <= 10^5 25 | 26 | /** 27 | * @param {number[]} nums 28 | * @return {number} 29 | */ 30 | var findNumbers = function(nums) { 31 | if (!nums.length) return 0; 32 | let count = 0; 33 | for(let i = 0; i < nums.length; i++){ 34 | if ((nums[i] + '').length % 2 === 0){ 35 | count++; 36 | } 37 | } 38 | return count 39 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/1299-easy-将每个元素替换为右侧最大元素.js: -------------------------------------------------------------------------------- 1 | // 1299. easy 将每个元素替换为右侧最大元素 2 | 3 | // 4 | // 给你一个数组 arr ,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1 替换。 5 | // 完成所有替换操作后,请你返回这个数组。 6 | // 7 | // 示例: 8 | // 9 | // 输入:arr = [17,18,5,4,6,1] 10 | // 输出:[18,6,6,6,1,-1] 11 | // 12 | // 提示: 13 | // 1 <= arr.length <= 10^4 14 | // 1 <= arr[i] <= 10^5 15 | 16 | 17 | /** 18 | * @param {number[]} arr 19 | * @return {number[]} 20 | */ 21 | var replaceElements = function(nums) { 22 | if (!nums.length) return []; 23 | let dp = []; 24 | for (let i = nums.length - 1; i >= 0; i--){ 25 | if (i === nums.length - 1) { 26 | dp[i] = -1; 27 | } else if (i === nums.length - 2){ 28 | dp[i] = nums[nums.length - 1]; 29 | } else { 30 | dp[i] = Math.max(nums[i + 1], dp[i + 1]) 31 | } 32 | } 33 | return dp; 34 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/1313-easy-解压缩编码列表.js: -------------------------------------------------------------------------------- 1 | // 1313 easy 解压缩编码列表 2 | 3 | // 给你一个以行程长度编码压缩的整数列表 nums 。 4 | // 考虑每相邻两个元素 [a, b] = [nums[2*i], nums[2*i+1]] (其中 i >= 0 ),每一对都表示解压后有 a 个值为 b 的元素。 5 | // 请你返回解压后的列表。 6 | // 7 | // 8 | // 示例: 9 | // 输入:nums = [1,2,3,4] 10 | // 输出:[2,4,4,4] 11 | //   12 | // 13 | // 提示: 14 | // 2 <= nums.length <= 100 15 | // nums.length % 2 == 0 16 | // 1 <= nums[i] <= 100 17 | 18 | 19 | /** 20 | * @param {number[]} nums 21 | * @return {number[]} 22 | */ 23 | var decompressRLElist = function(nums) { 24 | if(!nums.length) return []; 25 | let ans = []; 26 | for(let i = 0; i <= nums.length - 2; i = i + 2){ 27 | for(let j = 0; j < nums[i]; j++){ 28 | ans.push(nums[i+1]) 29 | } 30 | } 31 | return ans; 32 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/1375-medium-灯泡开关 III.js: -------------------------------------------------------------------------------- 1 | // 1375. 灯泡开关 III medium 2 | 3 | // 房间中有 n 枚灯泡,编号从 1 到 n,自左向右排成一排。最初,所有的灯都是关着的。 4 | // 5 | // 在 k  时刻( k 的取值范围是 0 到 n - 1),我们打开 light[k] 这个灯。 6 | // 7 | // 灯的颜色要想 变成蓝色 就必须同时满足下面两个条件: 8 | // 9 | // 灯处于打开状态。 10 | // 排在它之前(左侧)的所有灯也都处于打开状态。 11 | // 请返回能够让 所有开着的 灯都 变成蓝色 的时刻 数目 。 12 | // 13 | 14 | 15 | // 维护最大最小值,每次开灯check一下 16 | var numTimesAllBlue = function(light) { 17 | if(!light.length) return 0; 18 | let c = 0; 19 | let arr = [] 20 | let min = Number.MAX_SAFE_INTEGER; 21 | let max = 0; 22 | for(let i = 0; i < light.length; i++){ 23 | arr.push(light[i]) 24 | if (light[i] < min){ 25 | min = light[i] 26 | } 27 | if(light[i]>max){ 28 | max = light[i]; 29 | } 30 | // 每次开灯check一下。满足下面条件就是左侧全亮 31 | if(max === i+1 && min===1 && arr.length === i+1){ 32 | c++; 33 | } 34 | } 35 | return c; 36 | }; 37 | 38 | console.log(numTimesAllBlue([4,1,2,3])) 39 | -------------------------------------------------------------------------------- /数组类/unSortedArr/153-medium-寻找旋转排序数组中的最小值.js: -------------------------------------------------------------------------------- 1 | // 153 medium 寻找旋转排序数组中的最小值 2 | 3 | // 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 4 | // ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 5 | // 请找出其中最小的元素。 6 | // 你可以假设数组中不存在重复元素。 7 | // 8 | // 示例 1: 9 | // 输入: [3,4,5,1,2] 10 | // 输出: 1 11 | 12 | // 示例 2: 13 | // 输入: [4,5,6,7,0,1,2] 14 | // 输出: 0 15 | 16 | 17 | /** 18 | * @param {number[]} nums 19 | * @return {number} 20 | */ 21 | var findMin = function(nums) { 22 | return Math.min(...nums) 23 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/16-medium-最接近的三数之和.js: -------------------------------------------------------------------------------- 1 | // 16 medium 最接近的三数之和 2 | 3 | //给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 4 | // 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 5 | // 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 6 | // 7 | /** 8 | * @param {number[]} nums 9 | * @param {number} target 10 | * @return {number} 11 | */ 12 | var threeSumClosest = function(nums, target) { 13 | if(!nums.length) return 0; 14 | 15 | let close = Number.MAX_SAFE_INTEGER; 16 | for(let i = 0; i < nums.length; i++){ 17 | for(let j = i+1; j < nums.length; j++){ 18 | for(let k = j+1; k < nums.length; k++){ 19 | if (Math.abs(target - (nums[i] + nums[j] + nums[k])) < Math.abs(target- close)){ 20 | close = nums[i] + nums[j] + nums[k] 21 | } 22 | } 23 | } 24 | } 25 | return close 26 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/164-hard-最大间距.js: -------------------------------------------------------------------------------- 1 | // 164 hard 最大间距 2 | 3 | // 给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。 4 | // 5 | // 如果数组元素个数小于 2,则返回 0。 6 | // 7 | // 示例 1: 8 | // 输入: [3,6,9,1] 9 | // 输出: 3 10 | // 解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。 11 | 12 | // 示例 2: 13 | // 输入: [10] 14 | // 输出: 0 15 | // 解释: 数组元素个数小于 2,因此返回 0。 16 | 17 | // 说明: 18 | // 你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内。 19 | // 请尝试在线性时间复杂度和空间复杂度的条件下解决此问题。 20 | 21 | 22 | 23 | 24 | /** 25 | * @param {number[]} nums 26 | * @return {number} 27 | */ 28 | var maximumGap = function(nums) { 29 | if(nums.length <= 1) return 0; 30 | 31 | nums.sort((a, b) => { 32 | return a-b 33 | }) 34 | 35 | let max = 0 36 | for (let i = nums.length - 1; i >= 1; i--) { 37 | if (nums[i] - nums[i-1] > max){ 38 | max = nums[i] - nums[i-1] 39 | } 40 | } 41 | return max; 42 | }; 43 | 44 | console.log(maximumGap([1,10000000])) -------------------------------------------------------------------------------- /数组类/unSortedArr/169-easy-求众数.js: -------------------------------------------------------------------------------- 1 | // easy 求众数 169 2 | 3 | // 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 4 | // 5 | // 你可以假设数组是非空的,并且给定的数组总是存在众数。 6 | // 7 | // 示例 1: 8 | // 输入: [3,2,3] 9 | // 输出: 3 10 | 11 | // 示例 2: 12 | // 输入: [2,2,1,1,1,2,2] 13 | // 输出: 2 14 | 15 | /** 16 | * @param {number[]} nums 17 | * @return {number} 18 | */ 19 | var majorityElement = function(nums) { 20 | let count = Math.floor(nums.length / 2) 21 | let hash = {} 22 | for(let i = 0; i < nums.length; i++){ 23 | if (!hash[nums[i]]) {hash[nums[i]] = 1;} 24 | else{ 25 | hash[nums[i]]++; 26 | } 27 | if (hash[nums[i]] > count){ 28 | return nums[i] 29 | } 30 | } 31 | }; 32 | 33 | console.log(majorityElement([2,2,1,1,1,2,2])) -------------------------------------------------------------------------------- /数组类/unSortedArr/216-medium-组合总和3.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * @param {number} k 6 | * @param {number} n 7 | * @return {number[][]} 8 | */ 9 | var combinationSum3 = function(k, n) { 10 | if 11 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/217-isDepArr.js: -------------------------------------------------------------------------------- 1 | //217-easy-存在重复元素 2 | 3 | // 给定一个整数数组,判断是否存在重复元素。 4 | // 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 5 | // 6 | // 示例 1: 7 | // 输入: [1,2,3,1] 8 | // 输出: true 9 | 10 | // 示例 2: 11 | // 输入: [1,2,3,4] 12 | // 输出: false 13 | 14 | // 示例 3: 15 | // 输入: [1,1,1,3,3,4,3,2,4,2] 16 | // 输出: true 17 | 18 | /** 19 | * @param {number[]} nums 20 | * @return {boolean} 21 | */ 22 | var containsDuplicate = function(nums) { 23 | let set = new Set(nums) 24 | return set.size !== nums.length 25 | }; 26 | 27 | /** 28 | * 方法2 hashtable 29 | * @param {number[]} nums 30 | * @return {boolean} 31 | */ 32 | var containsDuplicate2 = function(nums) { 33 | if (!nums.length)return false 34 | let hash = {} 35 | for(let i = 0; i < nums.length; i++){ 36 | if (hash[nums[i]])return true 37 | hash[nums[i]] = true 38 | } 39 | return false 40 | }; 41 | 42 | console.log(containsDuplicate2([1,2,3,1])) -------------------------------------------------------------------------------- /数组类/unSortedArr/229-medium-求众数2.js: -------------------------------------------------------------------------------- 1 | // medium 229 求众数2 2 | // 3 | // 给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。 4 | // 说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。 5 | // 6 | // 示例 1: 7 | // 输入: [3,2,3] 8 | // 输出: [3] 9 | 10 | // 示例 2: 11 | // 输入: [1,1,1,3,3,2,2,2] 12 | // 输出: [1,2] 13 | 14 | 15 | /** 16 | * @param {number[]} nums 17 | * @return {number[]} 18 | */ 19 | var majorityElement = function(nums) { 20 | if (nums.length === 1) return nums; 21 | if (nums.length === 2) return nums[0] === nums[1] ? [nums[0]]: nums; 22 | 23 | let hash = {} 24 | for(let i = 0; i < nums.length; i++){ 25 | if (!hash[nums[i]]) hash[nums[i]] = 1; 26 | else{ 27 | hash[nums[i]]++ 28 | } 29 | } 30 | 31 | let resultArr = [] 32 | for (let key in hash){ 33 | if (hash[key] / nums.length > 1 / 3){ 34 | resultArr.push(Number(key)) 35 | } 36 | } 37 | return resultArr 38 | }; 39 | 40 | console.log(majorityElement([1,1,1,3,3,2,2,2])) -------------------------------------------------------------------------------- /数组类/unSortedArr/268-missingNumber.js: -------------------------------------------------------------------------------- 1 | //268 easy 缺失数字 2 | 3 | // 给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。 4 | // 5 | // 示例 1: 6 | // 输入: [3,0,1] 7 | // 输出: 2 8 | 9 | // 示例 2: 10 | // 输入: [9,6,4,2,3,5,7,0,1] 11 | // 输出: 8 12 | 13 | // 说明: 14 | // 你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现? 15 | 16 | 17 | /** 18 | * 高斯求和公式 19 | * @param {number[]} nums 20 | * @return {number} 21 | */ 22 | var missingNumber = function(nums) { 23 | let n = nums.length + 1 // 因为知道丢了一个数 24 | let sumAll = (0 + (n - 1)) * (n) / 2 25 | let sum2 = 0 26 | for(let i = 0; i < n - 1; i++){ 27 | sum2+=nums[i] 28 | } 29 | return sumAll - sum2 30 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/27-removeItem.js: -------------------------------------------------------------------------------- 1 | //leetcode-27-easy 2 | // 3 | // 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 4 | // 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 5 | // 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 6 | // 7 | // 示例 1: 8 | // 给定 nums = [3,2,2,3], val = 3, 9 | // 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 10 | // 你不需要考虑数组中超出新长度后面的元素。 11 | // 12 | // 示例 2: 13 | // 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 14 | // 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 15 | // 注意这五个元素可为任意顺序。 16 | // 你不需要考虑数组中超出新长度后面的元素。 17 | 18 | function delTargetItem(arr, target){ 19 | for (let i = arr.length; i >= 0; i--) { 20 | if (arr[i] === target) { 21 | arr.splice(i, 1) 22 | } 23 | } 24 | return arr.length 25 | } 26 | console.log(delTargetItem([3,2,2,3], 3)); 27 | console.log(delTargetItem([0,1,2,2,3,0,4,2], 2)); 28 | -------------------------------------------------------------------------------- /数组类/unSortedArr/283-moveZero.js: -------------------------------------------------------------------------------- 1 | //283-easy-移动0 2 | 3 | // 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 4 | // 5 | // 示例: 6 | // 输入: [0,1,0,3,12] 7 | // 输出: [1,3,12,0,0] 8 | 9 | // 说明: 10 | // 必须在原数组上操作,不能拷贝额外的数组。 11 | // 尽量减少操作次数。 12 | 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {void} Do not return anything, modify nums in-place instead. 17 | */ 18 | var moveZeroes = function(nums) { 19 | for(let i =nums.length; i >= 0; i--){ 20 | if (nums[i] === 0){ 21 | nums.splice(i, 1) 22 | nums.push(0) 23 | } 24 | } 25 | return nums 26 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/287-medium-寻找重复数.js: -------------------------------------------------------------------------------- 1 | // medium 287 寻找重复数 2 | 3 | // 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 4 | // 5 | // 示例 1: 6 | // 输入: [1,3,4,2,2] 7 | // 输出: 2 8 | 9 | // 示例 2: 10 | // 输入: [3,1,3,4,2] 11 | // 输出: 3 12 | 13 | // 说明: 14 | // 不能更改原数组(假设数组是只读的)。 15 | // 只能使用额外的 O(1) 的空间。 16 | // 时间复杂度小于 O(n2) 。 17 | // 数组中只有一个重复的数字,但它可能不止重复出现一次。 18 | 19 | 20 | /** 21 | * 高斯求和公式 22 | * @param {number[]} nums 23 | * @return {number} 24 | */ 25 | var findDuplicate = function (nums) { 26 | let hash = {} 27 | for(let i = 0; i < nums.length; i++){ 28 | if(!hash[nums[i]])hash[nums[i]] = 1 29 | else{ 30 | return nums[i] 31 | } 32 | } 33 | }; 34 | 35 | console.log(findDuplicate([1,3,4,2,2])) -------------------------------------------------------------------------------- /数组类/unSortedArr/315-hard-计算右侧小于当前元素的个数.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 最后一个case超时 5 | * @param {number[]} nums 6 | * @return {number[]} 7 | */ 8 | var countSmaller = function(nums) { 9 | let arr = [] 10 | for(let i = 0; i < nums.length; i++){ 11 | let count = 0; 12 | for(let j = i + 1; j < nums.length; j++){ 13 | if(nums[j] < nums[i]) count++; 14 | } 15 | arr.push(count) 16 | } 17 | return arr; 18 | }; 19 | 20 | 21 | 22 | console.log(countSmaller2([5,2,6,1])) -------------------------------------------------------------------------------- /数组类/unSortedArr/442-medium-数组中重复的数据.js: -------------------------------------------------------------------------------- 1 | // 442 medium 数组中重复的数据 2 | 3 | // 给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。 4 | // 找到所有出现两次的元素。 5 | // 你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗? 6 | // 7 | // 示例: 8 | // 输入: 9 | // [4,3,2,7,8,2,3,1] 10 | // 输出: 11 | // [2,3] 12 | 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number[]} 17 | */ 18 | var findDuplicates = function(nums) { 19 | let h = {} 20 | let arr = [] 21 | for(let i = 0; i < nums.length; i++){ 22 | if(!h[nums[i]]) h[nums[i]] = 1 23 | else { 24 | arr.push(nums[i]) 25 | } 26 | } 27 | return arr 28 | }; 29 | 30 | console.log(findDuplicates([4,3,2,7,8,2,3,1])) -------------------------------------------------------------------------------- /数组类/unSortedArr/462-medium-最少移动次数使数组元素相等 II.js: -------------------------------------------------------------------------------- 1 | // 462 medium 最小移动次数使数组元素相等2 2 | 3 | // 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 4 | // 您可以假设数组的长度最多为10000。 5 | // 6 | // 例如: 7 | // 输入: 8 | // [1,2,3] 9 | // 输出: 10 | // 2 11 | // 12 | // 说明: 13 | // 只有两个动作是必要的(记得每一步仅可使其中一个元素加1或减1): 14 | // [1,2,3] => [2,2,3] => [2,2,2] 15 | 16 | /** 17 | * @param {number[]} nums 18 | * @return {number} 19 | */ 20 | var minMoves2 = function(nums) { 21 | if(!nums.length)return 0; 22 | nums.sort((a, b) => { 23 | return a - b; 24 | }); 25 | let avg = nums[Math.floor(nums.length / 2)]; 26 | let res = 0; 27 | for(let i = 0; i < nums.length; i++){ 28 | res += Math.abs(nums[i] - avg) 29 | } 30 | return res; 31 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/5185-easy-存在连续三个奇数的数组.js: -------------------------------------------------------------------------------- 1 | 2 | //5185. 存在连续三个奇数的数组 easy 3 | 4 | //给你一个整数数组 arr,请你判断数组中是否存在连续三个元素都是奇数的情况:如果存在,请返回 true ;否则,返回 false 。 5 | // 6 | //   7 | // 8 | // 示例 1: 9 | // 10 | // 输入:arr = [2,6,4,1] 11 | // 输出:false 12 | // 解释:不存在连续三个元素都是奇数的情况。 13 | // 示例 2: 14 | // 15 | // 输入:arr = [1,2,34,3,4,5,7,23,12] 16 | // 输出:true 17 | // 解释:存在连续三个元素都是奇数的情况,即 [5,7,23] 。 18 | //   19 | // 20 | // 提示: 21 | // 22 | // 1 <= arr.length <= 1000 23 | // 1 <= arr[i] <= 1000 24 | // 25 | 26 | var threeConsecutiveOdds = function(arr) { 27 | if(arr.length < 3) return false; 28 | for(let i = 2; i < arr.length; i++){ 29 | if (arr[i] % 2 === 1 && arr[i-1] % 2 === 1 && arr[i-2] % 2 === 1) { 30 | return true; 31 | } 32 | } 33 | return false 34 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/5205-easy-独一无二的出现次数.js: -------------------------------------------------------------------------------- 1 | // 5205 easy 独一无二的出现次数 2 | 3 | // 给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。 4 | // 如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。 5 | // 6 | // 7 | // 示例 1: 8 | // 输入:arr = [1,2,2,1,1,3] 9 | // 输出:true 10 | // 解释:在该数组中,1 出现了 3 次,2 出现了 2 次,3 只出现了 1 次。没有两个数的出现次数相同。 11 | // 示例 2: 12 | // 输入:arr = [1,2] 13 | // 输出:false 14 | // 示例 3: 15 | // 输入:arr = [-3,0,1,-3,1,1,1,-3,10,0] 16 | // 输出:true 17 | // 18 | // 提示: 19 | // 1 <= arr.length <= 1000 20 | // -1000 <= arr[i] <= 1000 21 | 22 | 23 | /** 24 | * @param {number[]} arr 25 | * @return {boolean} 26 | */ 27 | var uniqueOccurrences = function(arr) { 28 | if(!arr.length) return true; 29 | arr.sort((a,b) => { 30 | return a-b 31 | }); 32 | 33 | let hash = {} 34 | for(let i = 0; i < arr.length; i++){ 35 | hash[arr[i]] = ~~(hash[arr[i]]) + 1; 36 | } 37 | // 判断hash里面有没有重复 38 | let a = Object.values(hash) 39 | return Array.from(new Set(a)).length === a.length; 40 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/5424-easy-数组中两元素的最大乘积.js: -------------------------------------------------------------------------------- 1 | //5424. 数组中两元素的最大乘积 easy 2 | 3 | //给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值。 4 | // 5 | // 请你计算并返回该式的最大值。 6 | // 7 | //   8 | // 9 | // 示例 1: 10 | // 11 | // 输入:nums = [3,4,5,2] 12 | // 输出:12 13 | // 解释:如果选择下标 i=1 和 j=2(下标从 0 开始),则可以获得最大值,(nums[1]-1)*(nums[2]-1) = (4-1)*(5-1) = 3*4 = 12 。 14 | // 示例 2: 15 | // 16 | // 输入:nums = [1,5,4,5] 17 | // 输出:16 18 | // 解释:选择下标 i=1 和 j=3(下标从 0 开始),则可以获得最大值 (5-1)*(5-1) = 16 。 19 | // 示例 3: 20 | // 21 | // 输入:nums = [3,7] 22 | // 输出:12 23 | //   24 | // 25 | // 提示: 26 | // 27 | // 2 <= nums.length <= 500 28 | // 1 <= nums[i] <= 10^3 29 | // 30 | 31 | var maxProduct = function(nums) { 32 | let m = Math.max(...nums); 33 | nums.splice(nums.indexOf(m),1) 34 | let n = Math.max(...nums); 35 | return (m-1) * (n-1) 36 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/5428-easy-重新排列数组.js: -------------------------------------------------------------------------------- 1 | // 5428. 重新排列数组 easy 2 | 3 | // 给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,...,xn,y1,y2,...,yn] 的格式排列。 4 | // 请你将数组按 [x1,y1,x2,y2,...,xn,yn] 格式重新排列,返回重排后的数组。 5 | // 6 | // 示例 1: 7 | // 输入:nums = [2,5,1,3,4,7], n = 3 8 | // 输出:[2,3,5,4,1,7] 9 | // 解释:由于 x1=2, x2=5, x3=1, y1=3, y2=4, y3=7 ,所以答案为 [2,3,5,4,1,7] 10 | // 示例 2: 11 | // 输入:nums = [1,2,3,4,4,3,2,1], n = 4 12 | // 输出:[1,4,2,3,3,2,4,1] 13 | // 示例 3: 14 | // 输入:nums = [1,1,2,2], n = 2 15 | // 输出:[1,2,1,2] 16 | // 17 | // 提示: 18 | // 1 <= n <= 500 19 | // nums.length == 2n 20 | // 1 <= nums[i] <= 10^3 21 | 22 | var shuffle = function(nums, n) { 23 | let a = []; 24 | for(let i = 0; i < n; i++){ 25 | a.push(nums[i]); 26 | a.push(nums[i+ n]); 27 | } 28 | return a; 29 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/5488-medium-使数组中所有元素相等的最小操作数.js: -------------------------------------------------------------------------------- 1 | 2 | //5488. 使数组中所有元素相等的最小操作数 medium 3 | 4 | // 存在一个长度为 n 的数组 arr ,其中 arr[i] = (2 * i) + 1 ( 0 <= i < n )。 5 | // 一次操作中,你可以选出两个下标,记作 x 和 y ( 0 <= x, y < n )并使 arr[x] 减去 1 、arr[y] 加上 1 (即 arr[x] -=1 且 arr[y] += 1 )。最终的目标是使数组中的所有元素都 相等 。题目测试用例将会 保证 :在执行若干步操作后,数组中的所有元素最终可以全部相等。 6 | // 给你一个整数 n,即数组的长度。请你返回使数组 arr 中所有元素相等所需的 最小操作数 。 7 | // 8 | //   9 | // 示例 1: 10 | // 输入:n = 3 11 | // 输出:2 12 | // 解释:arr = [1, 3, 5] 13 | // 第一次操作选出 x = 2 和 y = 0,使数组变为 [2, 3, 4] 14 | // 第二次操作继续选出 x = 2 和 y = 0,数组将会变成 [3, 3, 3] 15 | // 示例 2: 16 | // 输入:n = 6 17 | // 输出:9 18 | 19 | // 20 | // 提示: 21 | // 1 <= n <= 10^4 22 | 23 | var minOperations = function(n) { 24 | let avg 25 | if (n % 2 === 1){ 26 | avg = ~~(n / 2) * 2 + 1; 27 | }else { 28 | avg = (n / 2) * 2; 29 | } 30 | let res = 0; 31 | for(let i = 0; i < (n / 2); i++){ 32 | let d = avg - (i * 2 + 1); 33 | res += d; 34 | } 35 | return res; 36 | }; 37 | 38 | // console.log('111: ', minOperations(6)) -------------------------------------------------------------------------------- /数组类/unSortedArr/561-deArr.js: -------------------------------------------------------------------------------- 1 | // 给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。 2 | // 3 | // 示例 1: 4 | // 输入: [1,4,3,2] 5 | // 输出: 4 6 | // 解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4). 7 | 8 | // 提示: 9 | // n 是正整数,范围在 [1, 10000]. 10 | // 数组中的元素范围在 [-10000, 10000]. 11 | 12 | 13 | // 注意数组元素中有负数!!!导致直接sort()函数不对 14 | function f (arr) { 15 | arr.sort((a,b)=>{return a-b}) 16 | let sum = 0 17 | for (let i = 0; i < arr.length; i= i + 2) { 18 | sum+=arr[i] 19 | } 20 | return sum 21 | } 22 | console.log(f([-4, -3, -2, -1])); 23 | 24 | 25 | // bug 返回:[-1,-2,-3,-4] 26 | console.log([-4, -3, -2, -1].sort()); -------------------------------------------------------------------------------- /数组类/unSortedArr/628-3itemMultiMax.js: -------------------------------------------------------------------------------- 1 | // 628. 三个数的最大乘积 2 | 3 | // 给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。 4 | // 5 | // 示例 1: 6 | // 输入: [1,2,3] 7 | // 输出: 6 8 | // 9 | // 示例 2: 10 | // 输入: [1,2,3,4] 11 | // 输出: 24 12 | // 13 | // 注意: 14 | // 1.给定的整型数组长度范围是3-10000,数组中所有的元素范围是[-1000, 1000]。 15 | // 2.输入的数组中任意三个数的乘积不会超出32位有符号整数的范围。 16 | 17 | 18 | // 注意有负数。负数越小,负负得正的话,乘积越大 19 | function f (arr) { 20 | arr.sort((a,b)=>{return b-a}) 21 | return Math.max(arr[0] * arr[1] * arr[2], arr[0] * arr[arr.length - 1] * arr[arr.length - 2]) 22 | } 23 | console.log(f([1,2,3,4])); -------------------------------------------------------------------------------- /数组类/unSortedArr/714-medium-买卖股票的最佳时机含手续费.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * 5 | * @param {number[]} prices 6 | * @param {number} fee 7 | * @return {number} 8 | */ 9 | var maxProfit = function(prices, fee) { 10 | if (prices.length <= 1) return 0; 11 | 12 | let arr = [] 13 | let l = 0 14 | for(let i = 0; i < prices.length; i++){ 15 | if (prices[i] > prices[i+1] || i === prices.length - 1){ 16 | if (i - l > 0 && prices[i] - prices[l] > fee){ 17 | arr.push([l, i]) 18 | } 19 | // 移位到下一个单增区间的开始处 20 | l = i + 1; 21 | } 22 | } 23 | let result = 0 24 | for(let i = 0; i < arr.length; i++){ 25 | result += prices[arr[i][1]] - prices[arr[i][0]] 26 | } 27 | return result - fee * arr.length; 28 | }; 29 | 30 | console.log(maxProfit([1, 3, 2, 8, 4, 9], 2)) -------------------------------------------------------------------------------- /数组类/unSortedArr/78-medium-子集.js: -------------------------------------------------------------------------------- 1 | // 78 medium 子集 2 | 3 | // 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 4 | // 说明:解集不能包含重复的子集。 5 | // 6 | // 示例: 7 | // 输入: nums = [1,2,3] 8 | // 输出: 9 | // [ 10 | // [3], 11 | // [1], 12 | // [2], 13 | // [1,2,3], 14 | // [1,3], 15 | // [2,3], 16 | // [1,2], 17 | // [] 18 | // ] 19 | 20 | 21 | 22 | /** 23 | * @param {number[]} nums 24 | * @return {number[][]} 25 | */ 26 | var subsets = function(nums) { 27 | if(!nums.length) return [[]] 28 | let resultArr = [[], [nums[0]]] 29 | for(let i = 1; i < nums.length; i++){ 30 | let arr = [] 31 | for(let j = 0; j < resultArr.length; j++){ 32 | arr.push([nums[i], ...resultArr[j]]) 33 | } 34 | resultArr = resultArr.concat(arr) 35 | } 36 | return resultArr 37 | }; 38 | 39 | console.log(subsets([1,2,3])) -------------------------------------------------------------------------------- /数组类/unSortedArr/867-translateMatrix.js: -------------------------------------------------------------------------------- 1 | // 867 --easy --转置矩阵 2 | 3 | // 给定一个矩阵 A, 返回 A 的转置矩阵。 4 | // 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。 5 | // 6 | // 示例 1: 7 | // 输入:[[1,2,3],[4,5,6],[7,8,9]] 8 | // 输出:[[1,4,7],[2,5,8],[3,6,9]] 9 | 10 | // 示例 2: 11 | // 输入:[[1,2,3],[4,5,6]] 12 | // 输出:[[1,4],[2,5],[3,6]] 13 | // 14 | // 提示: 15 | // 1 <= A.length <= 1000 16 | // 1 <= A[0].length <= 1000 17 | 18 | 19 | /** 20 | * @param {number[][]} A 21 | * @return {number[][]} 22 | */ 23 | var transpose = function(A) { 24 | // [[1,2,3], 25 | // [4,5,6], 26 | // [7,8,9]] 27 | let newArr = [] 28 | for(let i = 0; i < A[0].length; i++){ 29 | newArr[i] = [] 30 | for(let j = 0; j < A.length; j++){ 31 | newArr[i].push(A[j][i]) 32 | } 33 | } 34 | return newArr 35 | }; 36 | 37 | console.log(transpose([[1,2,3],[4,5,6],[7,8,9]])) 38 | console.log(transpose([[1,2,3],[4,5,6]])) 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /数组类/unSortedArr/905-sortArrByOddAndEven.js: -------------------------------------------------------------------------------- 1 | // 给定一个非负整数数组 A,返回一个数组。在该数组中,A的所有偶数元素之后跟着所有奇数元素。 2 | // 你可以返回满足此条件的任何数组作为答案。 3 | // 4 | // 示例: 5 | // 输入:[3,1,2,4] 6 | // 输出:[2,4,3,1] 7 | // 输出 [4,2,3,1],[2,4,1,3] 和 [4,2,1,3] 也会被接受。 8 | 9 | function sortedArrByEvenAndOdd(arr){ 10 | let newArr = [] 11 | for (let i = 0; i < arr.length; i++) { 12 | if (arr[i] % 2 === 0){ 13 | newArr.unshift(arr[i]) 14 | } else { 15 | newArr.push(arr[i]) 16 | } 17 | } 18 | return newArr 19 | } 20 | console.log(sortedArrByEvenAndOdd([3,1,2,4])); -------------------------------------------------------------------------------- /数组类/unSortedArr/912-medium-排序数组.js: -------------------------------------------------------------------------------- 1 | // 912 medium 排序树组 2 | 3 | // 给定一个整数数组 nums,将该数组升序排列。 4 | // 5 | // 示例 1: 6 | // 输入:[5,2,3,1] 7 | // 输出:[1,2,3,5] 8 | 9 | // 示例 2: 10 | // 输入:[5,1,1,2,0,0] 11 | // 输出:[0,0,1,1,2,5] 12 | // 13 | // 提示: 14 | // 1 <= A.length <= 10000 15 | // -50000 <= A[i] <= 50000 16 | 17 | /** 18 | * @param {number[]} nums 19 | * @return {number[]} 20 | */ 21 | var sortArray = function(nums) { 22 | nums.sort((a, b)=>{ 23 | return a-b 24 | }) 25 | return nums 26 | }; -------------------------------------------------------------------------------- /数组类/unSortedArr/922-sortByOddAndEven.js: -------------------------------------------------------------------------------- 1 | // 922 easy 按奇偶排序数组 II 2 | 3 | // 给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。 4 | // 对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。 5 | // 你可以返回任何满足上述条件的数组作为答案。 6 | // 7 | // 示例: 8 | // 输入:[4,2,5,7] 9 | // 输出:[4,5,2,7] 10 | // 解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。 11 | //   12 | // 提示: 13 | // 2 <= A.length <= 20000 14 | // A.length % 2 == 0 15 | // 0 <= A[i] <= 1000 16 | 17 | /** 18 | * @param {number[]} A 19 | * @return {number[]} 20 | */ 21 | var sortArrayByParityII = function(A) { 22 | let newArr = [] 23 | let j = 0, k = 1; 24 | for(let i = A.length -1; i >= 0; i--){ 25 | if (A[i] % 2 === 0){ 26 | newArr[j] = A[i] 27 | j = j+2 28 | } else { 29 | newArr[k] = A[i] 30 | k = k+2 31 | } 32 | } 33 | return newArr 34 | }; 35 | 36 | console.log(sortArrayByParityII([4,2,5,7])) -------------------------------------------------------------------------------- /数组类/unSortedArr/945-medium-使数组唯一的最小增量.js: -------------------------------------------------------------------------------- 1 | // 945. 使数组唯一的最小增量 2 | 3 | // 给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。 4 | // 返回使 A 中的每个值都是唯一的最少操作次数。 5 | // 6 | // 示例 1: 7 | // 输入:[1,2,2] 8 | // 输出:1 9 | // 解释:经过一次 move 操作,数组将变为 [1, 2, 3]。 10 | // 示例 2: 11 | // 输入:[3,2,1,2,1,7] 12 | // 输出:6 13 | // 解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。 14 | // 可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。 15 | // 提示: 16 | // 0 <= A.length <= 40000 17 | // 0 <= A[i] < 40000 18 | 19 | /** 20 | * @param {number[]} A 21 | * @return {number} 22 | */ 23 | var minIncrementForUnique = function(A) { 24 | A.sort((a, b) => { 25 | return a - b 26 | }); 27 | let count = 0 28 | for(let i = 1; i < A.length; i++){ 29 | if(A[i] <= A[i-1]){ 30 | count = count + (A[i-1] + 1 - A[i]); 31 | A[i] = A[i-1] + 1; 32 | } 33 | } 34 | return count; 35 | }; 36 | 37 | console.log(minIncrementForUnique([3,2,1,2,1,7])) -------------------------------------------------------------------------------- /数组类/unSortedArr/989-easy-.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunzaizhuyi/js-leetcode/c3a12e4cd5991f970234595dc44f5942de768c85/数组类/unSortedArr/989-easy-.js -------------------------------------------------------------------------------- /数组类/前缀和/1480-easy-一维数组的动态和.js: -------------------------------------------------------------------------------- 1 | // 1480. 一维数组的动态和 easy 2 | 3 | // 给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。 4 | // 请返回 nums 的动态和。 5 | //   6 | // 7 | // 示例 1: 8 | // 输入:nums = [1,2,3,4] 9 | // 输出:[1,3,6,10] 10 | // 解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。 11 | // 示例 2: 12 | // 输入:nums = [1,1,1,1,1] 13 | // 输出:[1,2,3,4,5] 14 | // 解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。 15 | // 示例 3: 16 | // 输入:nums = [3,1,2,10,1] 17 | // 输出:[3,4,6,16,17] 18 | //   19 | // 20 | // 提示: 21 | // 1 <= nums.length <= 1000 22 | // -10^6 <= nums[i] <= 10^6 23 | 24 | 25 | var runningSum = function(nums) { 26 | if(!nums.length) return []; 27 | 28 | let sumArr = [nums[0]]; 29 | for(let i = 1; i < nums.length; i++){ 30 | sumArr.push(sumArr[i - 1] + nums[i]); 31 | } 32 | return sumArr; 33 | }; -------------------------------------------------------------------------------- /数组类/多个数组/LCP1-easy-猜数字.js: -------------------------------------------------------------------------------- 1 | // LCP1 easy 猜数字 2 | 3 | // 小A 和 小B 在玩猜数字。小B 每次从 1, 2, 3 中随机选择一个,小A 每次也从 1, 2, 3 中选择一个猜。 4 | // 他们一共进行三次这个游戏,请返回 小A 猜对了几次? 5 | // 输入的guess数组为 小A 每次的猜测,answer数组为 小B 每次的选择。guess和answer的长度都等于3。 6 | // 7 | // 示例 1: 8 | // 输入:guess = [1,2,3], answer = [1,2,3] 9 | // 输出:3 10 | // 解释:小A 每次都猜对了。 11 | // 12 | // 示例 2: 13 | // 输入:guess = [2,2,3], answer = [3,2,1] 14 | // 输出:1 15 | // 解释:小A 只猜对了第二次。 16 | // 17 | // 限制: 18 | // guess的长度 = 3 19 | // answer的长度 = 3 20 | // guess的元素取值为 {1, 2, 3} 之一。 21 | // answer的元素取值为 {1, 2, 3} 之一。 22 | 23 | 24 | 25 | /** 26 | * @param {number[]} guess 27 | * @param {number[]} answer 28 | * @return {number} 29 | */ 30 | var game = function(guess, answer) { 31 | let count = 0; 32 | for(let i = 0; i < guess.length; i++){ 33 | if(guess[i] === answer[i]) count++ 34 | } 35 | return count; 36 | }; -------------------------------------------------------------------------------- /数组类/多维数组/118-easy-杨辉三角1.js: -------------------------------------------------------------------------------- 1 | // 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 2 | // 在杨辉三角中,每个数是它左上方和右上方的数的和。 3 | // 4 | // 示例: 5 | // 输入: 5 6 | // 输出: 7 | // [ 8 | // [1], 9 | // [1,1], 10 | // [1,2,1], 11 | // [1,3,3,1], 12 | // [1,4,6,4,1] 13 | // ] 14 | 15 | function f(n){ 16 | if (n === 0) return [] 17 | if (n === 1) return [[1]] 18 | if (n === 2) return [[1], [1,1]] 19 | let result = [[1], [1,1]] 20 | for (let i = 3; i <= n; i++) { 21 | let preArr = result[i - 2] 22 | let iRow = [1] 23 | for (let j = 0; j <= preArr.length - 2; j++) { 24 | iRow.push(preArr[j] + preArr[j + 1]) 25 | } 26 | iRow.push(1) 27 | result.push(iRow) 28 | } 29 | return result 30 | } 31 | 32 | console.log(f(5)) -------------------------------------------------------------------------------- /数组类/多维数组/119-easy-杨辉三角2.js: -------------------------------------------------------------------------------- 1 | // 119 easy 杨辉三角2 2 | // 跟118的区别是只返回第N行,不用返回全部行 3 | 4 | /** 5 | * @param {number} rowIndex 6 | * @return {number[]} 7 | */ 8 | var getRow = function(rowIndex) { 9 | if (rowIndex === 0) return [1] 10 | if (rowIndex === 1) return [1,1] 11 | let result = [[1], [1,1]] 12 | for (let i = 2; i <= rowIndex; i++) { 13 | let preArr = result[i - 1] 14 | let iRow = [1] 15 | for (let j = 0; j <= preArr.length - 2; j++) { 16 | iRow.push(preArr[j] + preArr[j + 1]) 17 | } 18 | iRow.push(1) 19 | result.push(iRow) 20 | } 21 | return result[rowIndex] 22 | }; 23 | 24 | console.log(getRow(1)) -------------------------------------------------------------------------------- /数组类/多维数组/1351-easy-统计有序矩阵中的负数.js: -------------------------------------------------------------------------------- 1 | // 1351 easy 统计有序矩阵中的负数 2 | 3 | // 给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。  4 | // 请你统计并返回 grid 中 负数 的数目。 5 | // 6 | // 示例 1: 7 | // 输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]] 8 | // 输出:8 9 | // 解释:矩阵中共有 8 个负数。 10 | // 示例 2: 11 | // 输入:grid = [[3,2],[1,0]] 12 | // 输出:0 13 | // 示例 3: 14 | // 输入:grid = [[1,-1],[-1,-1]] 15 | // 输出:3 16 | // 示例 4: 17 | // 输入:grid = [[-1]] 18 | // 输出:1 19 | //   20 | // 21 | // 提示: 22 | // m == grid.length 23 | // n == grid[i].length 24 | // 1 <= m, n <= 100 25 | // -100 <= grid[i][j] <= 100 26 | 27 | 28 | var countNegatives = function(grid) { 29 | if (!grid.length) return 0; 30 | 31 | let count = 0; 32 | for(let i = 0; i < grid.length; i++){ 33 | for(let j = 0; j < grid[0].length; j++){ 34 | if (grid[i][j] < 0){ 35 | count++; 36 | } 37 | } 38 | } 39 | return count; 40 | }; 41 | -------------------------------------------------------------------------------- /数组类/多维数组/1572-easy-矩阵对角线元素的和.js: -------------------------------------------------------------------------------- 1 | // 1572. 矩阵对角线元素的和 easy 2 | 3 | // 给你一个正方形矩阵 mat,请你返回矩阵对角线元素的和。 4 | // 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 5 | 6 | 7 | //提示: 8 | // n == mat.length == mat[i].length 9 | // 1 <= n <= 100 10 | // 1 <= mat[i][j] <= 100 11 | 12 | /** 13 | * @param {number[][]} mat 14 | * @return {number} 15 | */ 16 | var diagonalSum = function(mat) { 17 | let sum = 0; 18 | for(let i = 0; i < mat.length; i++){ 19 | for(let j = 0; j < mat[0].length; j++){ 20 | if(i ===j || i + j === mat.length - 1){ 21 | sum += mat[i][j]; 22 | } 23 | } 24 | } 25 | return sum; 26 | }; 27 | 28 | console.log('111: ', diagonalSum([[1,2,3],[4,5,6],[7,8,9]])); // 25 -------------------------------------------------------------------------------- /数组类/多维数组/378-medium-有序矩阵中第k小的元素.js: -------------------------------------------------------------------------------- 1 | // 378. 有序矩阵中第K小的元素 medium 2 | 3 | // 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。 4 | // 请注意,它是排序后的第k小元素,而不是第k个元素。 5 | // 6 | // 示例: 7 | // 8 | // matrix = [ 9 | // [ 1, 5, 9], 10 | // [10, 11, 13], 11 | // [12, 13, 15] 12 | // ], 13 | // k = 8, 14 | // 15 | // 返回 13。 16 | // 说明: 17 | // 你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n2 。 18 | 19 | 20 | /** 21 | * @param {number[][]} matrix 22 | * @param {number} k 23 | * @return {number} 24 | */ 25 | var kthSmallest = function(matrix, k) { 26 | // 拉平数组 27 | let arr = [] 28 | for(let i = 0; i < matrix.length; i++){ 29 | arr.push(...matrix[i]) 30 | } 31 | arr.sort((a, b) => { 32 | return a-b 33 | }) 34 | return arr[k-1] 35 | }; -------------------------------------------------------------------------------- /日期问题/1360-easy-日期之间间隔几天.js: -------------------------------------------------------------------------------- 1 | // 1360 easy 日期之间隔几天 2 | 3 | // 请你编写一个程序来计算两个日期之间隔了多少天。 4 | // 日期以字符串形式给出,格式为 YYYY-MM-DD,如示例所示。 5 | // 6 | // 示例 1: 7 | // 输入:date1 = "2019-06-29", date2 = "2019-06-30" 8 | // 输出:1 9 | // 示例 2: 10 | // 输入:date1 = "2020-01-15", date2 = "2019-12-31" 11 | // 输出:15 12 | //   13 | // 提示: 14 | // 给定的日期是 1971 年到 2100 年之间的有效日期。 15 | 16 | // 1360. 日期之间隔几天 17 | var daysBetweenDates = function(date1, date2) { 18 | let d1 = new Date(date1); 19 | let d2 = new Date(date2); 20 | let dif = d1.getTime() - d2.getTime(); 21 | let day = 60 * 60 * 24 * 1000; 22 | return Math.abs(~~(dif / day)); 23 | }; 24 | 25 | // console.log(daysBetweenDates("2020-01-15", "2019-12-31")) -------------------------------------------------------------------------------- /栈/503-medium-下一个更大元素2.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * @param {number[]} nums 6 | * @return {number[]} 7 | */ 8 | var nextGreaterElements = function(nums) { 9 | 10 | }; 11 | 12 | console.log(nextGreaterElements([5,4,3,2,1])) 13 | -------------------------------------------------------------------------------- /栈/844-easy-比较含退格的字符串.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /** 5 | * 栈解法 6 | * @param {string} S 7 | * @param {string} T 8 | * @return {boolean} 9 | */ 10 | var backspaceCompare = function(S, T) { 11 | 12 | let getStack = (S) => { 13 | let s = [] 14 | for(let i = 0; i < S.length; i++){ 15 | if (!s.length){ 16 | if (S[i] !== '#'){ 17 | s.push(S[i]) 18 | } 19 | } else { 20 | if (S[i] === '#'){ 21 | s.pop() 22 | } else { 23 | s.push(S[i]) 24 | } 25 | } 26 | } 27 | return s; 28 | } 29 | let stack1 = getStack(S) 30 | let stack2 = getStack(T) 31 | 32 | return stack1.join('') === stack2.join('') 33 | }; 34 | 35 | console.log(backspaceCompare('ab#c', "ad#c")) -------------------------------------------------------------------------------- /栈题目.md: -------------------------------------------------------------------------------- 1 | ## 栈 2 | 3 | * 20 easy 有效的括号 4 | * 155 easy 最小栈 5 | * 225 easy 用队列实现栈 6 | * 394 medium 字符串解码 7 | * 496 easy 下一个更大元素1 8 | * 503 medium 下一个更大元素2 9 | * 844 easy 比较含退格的字符串 10 | * 921 medium 使括号有效的最少添加 11 | * 1124 medium 表现良好的最长时间段 12 | * 1047 easy 删除字符串中的所有相邻重复项 13 | * 5357 medium 设计一个支持增量操作的栈 -------------------------------------------------------------------------------- /树/二叉树/100-easy-相同的树.js: -------------------------------------------------------------------------------- 1 | //100 easy 相同的树 2 | 3 | //给定两个二叉树,编写一个函数来检验它们是否相同。 4 | // 5 | // 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 6 | 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} p 16 | * @param {TreeNode} q 17 | * @return {boolean} 18 | */ 19 | var isSameTree = function(p, q) { 20 | let fn = (a, b) => { 21 | if(!a && !b) return true; 22 | if(!a && b) { 23 | return false; 24 | } 25 | if(a && !b){ 26 | return false; 27 | } 28 | if(a.val !== b.val) { 29 | return false; 30 | } 31 | return fn(a.left, b.left) && fn(a.right, b.right) 32 | }; 33 | return fn(p, q); 34 | }; -------------------------------------------------------------------------------- /树/二叉树/101-easy-对称二叉树.js: -------------------------------------------------------------------------------- 1 | 2 | // 101 easy 对称二叉树 3 | //给定一个二叉树,检查它是否是镜像对称的。 4 | 5 | /** 6 | * Definition for a binary tree node. 7 | * function TreeNode(val) { 8 | * this.val = val; 9 | * this.left = this.right = null; 10 | * } 11 | */ 12 | /** 13 | * @param {TreeNode} root 14 | * @return {boolean} 15 | */ 16 | var isSymmetric = function(root) { 17 | 18 | let isMirror = (a, b) => { 19 | if(!a)return true; 20 | if(!a && !b)return true; 21 | if(!a || !b)return false; 22 | return (a.val === b.val) && isMirror(a.left, b.right) && isMirror(a.right, b.left) 23 | } 24 | return isMirror(root, root) 25 | }; -------------------------------------------------------------------------------- /树/二叉树/104-easy-二叉树的最大深度.js: -------------------------------------------------------------------------------- 1 | // 104 easy 二叉树的最大深度 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 | 20 | /** 21 | * Definition for a binary tree node. 22 | * function TreeNode(val) { 23 | * this.val = val; 24 | * this.left = this.right = null; 25 | * } 26 | */ 27 | 28 | 29 | /** 30 | * @param {TreeNode} root 31 | * @return {number} 32 | */ 33 | var maxDepth = function(root) { 34 | if (root === null){ 35 | return 0; 36 | } 37 | return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; 38 | }; 39 | -------------------------------------------------------------------------------- /树/二叉树/114-medium-二叉树展开成链表.js: -------------------------------------------------------------------------------- 1 | 2 | // 114 medium 二叉树展开成链表 3 | 4 | //给定一个二叉树,原地将它展开为链表。 5 | 6 | 7 | 8 | /** 9 | * @param {TreeNode} root 10 | * @return {void} Do not return anything, modify root in-place instead. 11 | */ 12 | var flatten = function(root) { 13 | // 思路:将右子树挂在左子树最右的叶子节点上;将左子树放到右子树;递归前两步 14 | if(!root)return; 15 | let node = root; 16 | while(node){ 17 | // 没有左子树,直接往下递归 18 | if (!node.left){ 19 | node = node.right; 20 | continue; 21 | } 22 | // 拿到右子树 23 | let r = node.right; 24 | let l = node.left; 25 | // 找到左子树最右叶子 26 | let leaf = node.left; 27 | while(leaf.right){ 28 | leaf = leaf.right; 29 | } 30 | // 把右子树 挂 左子树最右叶节点 31 | leaf.right = r; 32 | // 将左子树放到右子树 33 | node.right = l; 34 | node.left = null; // 别忘了 35 | 36 | // 递归下一个节点 37 | node = node.right; 38 | } 39 | }; -------------------------------------------------------------------------------- /树/二叉树/1302-medium-层数最深叶子节点的和.js: -------------------------------------------------------------------------------- 1 | //1302. 层数最深叶子节点的和 medium 2 | 3 | //给你一棵二叉树,请你返回层数最深的叶子节点的和。 4 | 5 | 6 | // 宽度优先搜索BFS 解法 7 | var deepestLeavesSum = (root) => { 8 | if (!root) return 0; 9 | let bfs = (nodes) => { 10 | let result = []; 11 | let hasSonNodes = [] 12 | for (let i = 0; i < nodes.length; i++){ 13 | if (!nodes[i].left && !nodes[i].right){ 14 | result.push(nodes[i].val) 15 | } else { 16 | if (nodes[i].left){ 17 | hasSonNodes.push(nodes[i].left); 18 | } 19 | if(nodes[i].right){ 20 | hasSonNodes.push(nodes[i].right); 21 | } 22 | } 23 | } 24 | if (!hasSonNodes.length){ 25 | return result; 26 | } 27 | return bfs(hasSonNodes) 28 | } 29 | let result = bfs([root]) 30 | 31 | return result.reduce((p, n) => { 32 | return p + n; 33 | }, 0) 34 | } -------------------------------------------------------------------------------- /树/二叉树/1379-medium-找出克隆二叉树中的相同节点.js: -------------------------------------------------------------------------------- 1 | 2 | //1379. 找出克隆二叉树中的相同节点 medium 3 | 4 | // 给你两棵二叉树,原始树 original 和克隆树 cloned,以及一个位于原始树 original 中的目标节点 target。 5 | // 其中,克隆树 cloned 是原始树 original 的一个 副本 。 6 | // 请找出在树 cloned 中,与 target 相同 的节点,并返回对该节点的引用(在 C/C++ 等有指针的语言中返回 节点指针,其他语言返回节点本身)。 7 | // 8 | // 9 | // 注意: 10 | // 你 不能 对两棵二叉树,以及 target 节点进行更改。 11 | // 只能 返回对克隆树 cloned 中已有的节点的引用。 12 | // 进阶:如果树中允许出现值相同的节点,你将如何解答? 13 | 14 | 15 | // 其实就是遍历一下 16 | var getTargetCopy = function(original, cloned, target) { 17 | let res; 18 | let dfs = (node) => { 19 | if (!node) return; 20 | if(node.val === target.val){ 21 | res = node; 22 | return; 23 | } 24 | dfs(node.left); 25 | dfs(node.right); 26 | } 27 | dfs(cloned); 28 | return res; 29 | }; -------------------------------------------------------------------------------- /树/二叉树/144-medium-二叉树的先序遍历.js: -------------------------------------------------------------------------------- 1 | // 144 medium 二叉树的先序遍历 2 | 3 | // 给定一个二叉树,返回它的 前序 遍历。 4 | // 5 | //  示例: 6 | // 7 | // 输入: [1,null,2,3] 8 | // 1 9 | // \ 10 | // 2 11 | // / 12 | // 3 13 | // 14 | // 输出: [1,2,3] 15 | // 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 16 | 17 | 18 | 19 | 20 | /** 21 | * Definition for a binary tree node. 22 | * function TreeNode(val) { 23 | * this.val = val; 24 | * this.left = this.right = null; 25 | * } 26 | */ 27 | /** 28 | * @param {TreeNode} root 29 | * @return {number[]} 30 | */ 31 | var preorderTraversal = function(root) { 32 | if (!root) return []; 33 | let arr = [] 34 | let curNode = root; 35 | let fn = (curNode) => { 36 | arr.push(curNode.val) 37 | if (curNode.left){ 38 | fn(curNode.left) 39 | } 40 | if (curNode.right){ 41 | fn(curNode.right) 42 | } 43 | } 44 | fn(curNode) 45 | return arr; 46 | }; -------------------------------------------------------------------------------- /树/二叉树/145-hard-二叉树的后序遍历.js: -------------------------------------------------------------------------------- 1 | // 145 hard 二叉树的后序遍历 2 | 3 | // 给定一个二叉树,返回它的 后序 遍历。 4 | // 5 | // 示例: 6 | // 7 | // 输入: [1,null,2,3] 8 | // 1 9 | // \ 10 | // 2 11 | // / 12 | // 3 13 | // 14 | // 输出: [3,2,1] 15 | // 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 16 | // 17 | 18 | 19 | 20 | /** 21 | * Definition for a binary tree node. 22 | * function TreeNode(val) { 23 | * this.val = val; 24 | * this.left = this.right = null; 25 | * } 26 | */ 27 | /** 28 | * @param {TreeNode} root 29 | * @return {number[]} 30 | */ 31 | var postorderTraversal = function(root) { 32 | if (!root) return []; 33 | let arr = [] 34 | let curNode = root; 35 | let fn = (curNode) => { 36 | if (curNode.left){ 37 | fn(curNode.left) 38 | } 39 | if (curNode.right){ 40 | fn(curNode.right) 41 | } 42 | arr.push(curNode.val) 43 | } 44 | fn(curNode) 45 | return arr 46 | }; -------------------------------------------------------------------------------- /树/二叉树/199-medium-二叉树的右视图.js: -------------------------------------------------------------------------------- 1 | // 199 medium 二叉树的右视图 2 | 3 | // 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 4 | 5 | 6 | /** 7 | * Definition for a binary tree node. 8 | * function TreeNode(val) { 9 | * this.val = val; 10 | * this.left = this.right = null; 11 | * } 12 | */ 13 | /** 14 | * push每一层的最右节点 15 | * @param {TreeNode} root 16 | * @return {number[]} 17 | */ 18 | var rightSideView = function(root) { 19 | if(!root)return [] 20 | 21 | let arr = [] 22 | let fn = (nodeArr) => { 23 | let nextLevel = [] 24 | arr.push(nodeArr[nodeArr.length - 1].val) 25 | nodeArr.forEach((node, index) => { 26 | if(node.left){ 27 | nextLevel.push(node.left); 28 | } 29 | if(node.right){ 30 | nextLevel.push(node.right); 31 | } 32 | }); 33 | // 退出条件 34 | if(nextLevel.length){fn(nextLevel)} 35 | } 36 | fn([root]) 37 | return arr 38 | }; -------------------------------------------------------------------------------- /树/二叉树/230-medium-二叉搜索树中的第K小的元素.js: -------------------------------------------------------------------------------- 1 | // 230. 二叉搜索树中第K小的元素 medium 2 | 3 | // 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。 4 | // 5 | // 说明: 6 | // 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。 7 | 8 | 9 | /** 10 | * Definition for a binary tree node. 11 | * function TreeNode(val) { 12 | * this.val = val; 13 | * this.left = this.right = null; 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @param {number} k 19 | * @return {number} 20 | */ 21 | var kthSmallest = function(root, k) { 22 | if(!root) return null; 23 | let arr = [] 24 | let fn = (cNode) => { 25 | // 碰到叶子节点 26 | if(!cNode.left && !cNode.right){ 27 | arr.push(cNode.val) 28 | return; 29 | } 30 | if(cNode.left){ 31 | fn(cNode.left) 32 | } 33 | arr.push(cNode.val) 34 | if(cNode.right){ 35 | fn(cNode.right) 36 | } 37 | } 38 | fn(root); 39 | return arr[k-1] 40 | }; -------------------------------------------------------------------------------- /树/二叉树/404-easy-左叶子之和.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * function TreeNode(val) { 6 | * this.val = val; 7 | * this.left = this.right = null; 8 | * } 9 | */ 10 | /** 11 | * @param {TreeNode} root 12 | * @return {number} 13 | */ 14 | var sumOfLeftLeaves = function(root) { 15 | if(!root) return 0; 16 | let sum = 0; 17 | 18 | 19 | let fn = (curNode) => { 20 | if(curNode.left && (!curNode.left.left && !curNode.left.right)){ 21 | sum += curNode.left.val; 22 | 23 | } 24 | if(curNode.left){ 25 | fn(curNode.left) 26 | } 27 | if(curNode.right){ 28 | fn(curNode.right) 29 | } 30 | } 31 | fn(root) 32 | return sum; 33 | }; -------------------------------------------------------------------------------- /树/二叉树/589-easy-N叉树的先序遍历.js: -------------------------------------------------------------------------------- 1 | // 589 easy N叉树的先序遍历 2 | // 3 | // 给定一个 N 叉树,返回其节点值的前序遍历。 4 | // 例如,给定一个 3叉树 : 5 | // 6 | // 7 | // 8 | // 9 | // 10 | // 11 | // 12 | // 返回其前序遍历: [1,3,5,6,2,4]。 13 | // 14 | // 说明: 递归法很简单,你可以使用迭代法完成此题吗? 15 | 16 | 17 | 18 | /** 19 | * // Definition for a Node. 20 | * function Node(val,children) { 21 | * this.val = val; 22 | * this.children = children; 23 | * }; 24 | */ 25 | /** 26 | * @param {Node} root 27 | * @return {number[]} 28 | */ 29 | var preorder = function(root) { 30 | if (!root) return [] 31 | let arr = [] 32 | let curNode = root 33 | let fn = (curNode) => { 34 | arr.push(curNode.val); 35 | if (curNode.children.length){ 36 | for(let i = 0; i < curNode.children.length; i++){ 37 | fn(curNode.children[i]) 38 | } 39 | } 40 | } 41 | fn(curNode) 42 | return arr 43 | }; -------------------------------------------------------------------------------- /树/二叉树/590-easy-N叉树的后序遍历.js: -------------------------------------------------------------------------------- 1 | // 590 easy N叉树的后序遍历 2 | 3 | // 给定一个 N 叉树,返回其节点值的后序遍历。 4 | // 5 | // 例如,给定一个 3叉树 : 6 | // 7 | // 8 | // 9 | // 10 | // 11 | // 12 | // 13 | // 返回其后序遍历: [5,6,3,2,4,1]. 14 | // 15 | // 16 | // 17 | // 说明: 递归法很简单,你可以使用迭代法完成此题吗? 18 | 19 | 20 | /** 21 | * // Definition for a Node. 22 | * function Node(val,children) { 23 | * this.val = val; 24 | * this.children = children; 25 | * }; 26 | */ 27 | /** 28 | * @param {Node} root 29 | * @return {number[]} 30 | */ 31 | var postorder = function(root) { 32 | if (!root) return [] 33 | let arr = [] 34 | let curNode = root 35 | let fn = (curNode) => { 36 | if (curNode.children.length){ 37 | for(let i = 0; i < curNode.children.length; i++){ 38 | fn(curNode.children[i]) 39 | } 40 | } 41 | arr.push(curNode.val); 42 | } 43 | fn(curNode) 44 | return arr 45 | }; -------------------------------------------------------------------------------- /树/二叉树/783-easy-二叉搜索树结点最小距离.js: -------------------------------------------------------------------------------- 1 | // 783 easy 2 | // 跟530一模一样,代码不用改 3 | // 4 | // 给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。 5 | // 6 | // 示例: 7 | // 8 | // 输入: root = [4,2,6,1,3,null,null] 9 | // 输出: 1 10 | // 解释: 11 | // 注意,root是树结点对象(TreeNode object),而不是数组。 12 | // 13 | // 给定的树 [4,2,6,1,3,null,null] 可表示为下图: 14 | // 15 | // 4 16 | // / \ 17 | // 2 6 18 | // / \ 19 | // 1 3 20 | // 21 | // 最小的差值是 1, 它是节点1和节点2的差值, 也是节点3和节点2的差值。 22 | // 注意: 23 | // 24 | // 二叉树的大小范围在 2 到 100。 25 | // 二叉树总是有效的,每个节点的值都是整数,且不重复。 26 | -------------------------------------------------------------------------------- /树/二叉树/814-medium-二叉树剪枝.js: -------------------------------------------------------------------------------- 1 | // 814 medium 二叉树剪枝 2 | 3 | // 给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1。 4 | // 返回移除了所有不包含 1 的子树的原二叉树。 5 | // ( 节点 X 的子树为 X 本身,以及所有 X 的后代。) 6 | 7 | 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val) { 11 | * this.val = val; 12 | * this.left = this.right = null; 13 | * } 14 | */ 15 | /** 16 | * @param {TreeNode} root 17 | * @return {TreeNode} 18 | */ 19 | var pruneTree = function(root) { 20 | if(!root)return root; 21 | if(root.left){ 22 | pruneTree(root.left); 23 | } 24 | if(root.right){ 25 | pruneTree(root.right); 26 | } 27 | if(root.left){ 28 | if(!root.left.left && !root.left.right && root.left.val === 0) root.left = null 29 | } 30 | if(root.right){ 31 | if(!root.right.left && !root.right.right && root.right.val === 0) root.right = null 32 | } 33 | return root; 34 | }; -------------------------------------------------------------------------------- /树/二叉树/94-medium-二叉树的中序遍历.js: -------------------------------------------------------------------------------- 1 | // 94 medium 二叉树的中序遍历 2 | 3 | // 给定一个二叉树,返回它的中序 遍历。 4 | // 5 | // 示例: 6 | // 7 | // 输入: [1,null,2,3] 8 | // 1 9 | // \ 10 | // 2 11 | // / 12 | // 3 13 | // 14 | // 输出: [1,3,2] 15 | // 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 16 | 17 | 18 | /** 19 | * Definition for a binary tree node. 20 | * function TreeNode(val) { 21 | * this.val = val; 22 | * this.left = this.right = null; 23 | * } 24 | */ 25 | /** 26 | * @param {TreeNode} root 27 | * @return {number[]} 28 | */ 29 | var inorderTraversal = function(root) { 30 | if (!root) return []; 31 | let arr = [] 32 | let curNode = root; 33 | let fn = (curNode) => { 34 | if (curNode.left){ 35 | fn(curNode.left) 36 | } 37 | arr.push(curNode.val) 38 | if (curNode.right){ 39 | fn(curNode.right) 40 | } 41 | } 42 | fn(curNode) 43 | return arr; 44 | }; -------------------------------------------------------------------------------- /树/二叉树/98-medium-验证二叉搜索树.js: -------------------------------------------------------------------------------- 1 | 2 | // 98. 验证二叉搜索树 medium 3 | 4 | //给定一个二叉树,判断其是否是一个有效的二叉搜索树。 5 | // 6 | // 假设一个二叉搜索树具有如下特征: 7 | // 8 | // 节点的左子树只包含小于当前节点的数。 9 | // 节点的右子树只包含大于当前节点的数。 10 | // 所有左子树和右子树自身必须也是二叉搜索树。 11 | // 示例 1: 12 | // 13 | // 输入: 14 | // 2 15 | // / \ 16 | // 1 3 17 | // 输出: true 18 | // 示例 2: 19 | // 20 | // 输入: 21 | // 5 22 | // / \ 23 | // 1 4 24 | //   / \ 25 | //   3 6 26 | // 输出: false 27 | // 解释: 输入为: [5,1,4,null,null,3,6]。 28 | //   根节点的值为 5 ,但是其右子节点值为 4 。 29 | 30 | 31 | var isValidBST = function(root) { 32 | if (!root) return true; 33 | let res = [] 34 | let fn = (node)=>{ 35 | if (!node) return; 36 | fn(node.left); 37 | res.push(node.val); 38 | fn(node.right); 39 | } 40 | fn(root); 41 | for(let i=1;i=res[i]){return false} 43 | } 44 | return true; 45 | }; -------------------------------------------------------------------------------- /程序员面试金典/01.01-easy-判定字符是否唯一.js: -------------------------------------------------------------------------------- 1 | // 面试题 01.01. 判定字符是否唯一 easy 2 | 3 | //实现一个算法,确定一个字符串 s 的所有字符是否全都不同。 4 | // 5 | // 示例 1: 6 | // 7 | // 输入: s = "leetcode" 8 | // 输出: false 9 | // 示例 2: 10 | // 11 | // 输入: s = "abc" 12 | // 输出: true 13 | // 限制: 14 | // 15 | // 0 <= len(s) <= 100 16 | // 如果你不使用额外的数据结构,会很加分。 17 | 18 | 19 | var isUnique = function(astr) { 20 | // 哈希表解法 21 | if (!astr.length) return true; 22 | let hash = {}; 23 | for(let i = 0; i < astr.length; i++){ 24 | if (hash[astr[i]]){ 25 | return false; 26 | }else { 27 | hash[astr[i]] = true; 28 | } 29 | } 30 | return true; 31 | }; -------------------------------------------------------------------------------- /程序员面试金典/01.02-easy-判定是否互为字符重排.js: -------------------------------------------------------------------------------- 1 | // 面试题 01.02. 判定是否互为字符重排 easy 2 | 3 | 4 | //给定两个字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 5 | // 6 | // 示例 1: 7 | // 8 | // 输入: s1 = "abc", s2 = "bca" 9 | // 输出: true 10 | // 示例 2: 11 | // 12 | // 输入: s1 = "abc", s2 = "bad" 13 | // 输出: false 14 | // 说明: 15 | // 16 | // 0 <= len(s1) <= 100 17 | // 0 <= len(s2) <= 100 18 | 19 | var checkPermutation = function(s1, s2) { 20 | if (s1.length !== s2.length) return false; 21 | 22 | // 遍历s1,遇到每个共有字符,s2删除之。 23 | let arr2 = s2.split(''); 24 | for(let i = 0; i < s1.length; i++){ 25 | // 遇到仅仅s1有的字符,返回false 26 | if (arr2.indexOf(s1[i]) === -1) return false; 27 | arr2.splice(arr2.indexOf(s1[i]), 1); 28 | } 29 | return true; 30 | }; -------------------------------------------------------------------------------- /程序员面试金典/01.09-easy-字符串轮转.js: -------------------------------------------------------------------------------- 1 | 2 | // 面试题 01.09. 字符串轮转 3 | 4 | //字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。 5 | // 6 | // 示例1: 7 | // 8 | // 输入:s1 = "waterbottle", s2 = "erbottlewat" 9 | // 输出:True 10 | // 示例2: 11 | // 12 | // 输入:s1 = "aa", "aba" 13 | // 输出:False 14 | // 提示: 15 | // 16 | // 字符串长度在[0, 100000]范围内。 17 | // 说明: 18 | // 19 | // 你能只调用一次检查子串的方法吗? 20 | 21 | 22 | var isFlipedString = function(s1, s2) { 23 | if (s1.length !== s2.length) return false; 24 | if (s1 === s2) return true; 25 | s1 += s1; 26 | return s1.indexOf(s2) >= 0; 27 | }; -------------------------------------------------------------------------------- /程序员面试金典/02.02-easy-返回倒数第 k 个节点.js: -------------------------------------------------------------------------------- 1 | // 面试题 02.02. 返回倒数第 k 个节点 2 | 3 | // 实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。 4 | // 注意:本题相对原题稍作改动 5 | // 6 | // 示例: 7 | // 输入: 1->2->3->4->5 和 k = 2 8 | // 输出: 4 9 | // 说明: 10 | // 给定的 k 保证是有效的。 11 | // 12 | var kthToLast = function(head, k) { 13 | // 两个指针。 14 | let slow = head; 15 | let fast = head; 16 | let i = 0 17 | while(i <= k - 1){ 18 | fast = fast.next; 19 | i++; 20 | } 21 | while(fast){ 22 | fast = fast.next; 23 | slow = slow.next; 24 | } 25 | return slow.val; 26 | }; -------------------------------------------------------------------------------- /程序员面试金典/04.06-medium-后继者.js: -------------------------------------------------------------------------------- 1 | //04.06. 后继者 2 | 3 | //设计一个算法,找出二叉搜索树中指定节点的“下一个”节点(也即中序后继)。 4 | // 如果指定节点没有对应的“下一个”节点,则返回null。 5 | 6 | var inorderSuccessor = function(root, p) { 7 | let arr = []; 8 | let dfs = (node) => { 9 | if(!node)return; 10 | dfs(node.left); 11 | arr.push(node.val); 12 | dfs(node.right); 13 | }; 14 | dfs(root); 15 | if(arr.indexOf(p.val) === arr.length-1)return null; 16 | 17 | // 找节点 18 | let des = arr[arr.indexOf(p.val) + 1]; 19 | let res; 20 | let fn = (node) => { 21 | if(!node)return; 22 | if(node.val === des){res = node;return } 23 | fn(node.left); 24 | fn(node.right); 25 | }; 26 | fn(root); 27 | return res; 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /程序员面试金典/05.01-easy-插入.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | //插入。给定两个32位的整数N与M,以及表示比特位置的i与j。编写一种方法,将M插入N,使得M从N的第j位开始,到第i位结束。 4 | // 假定从j位到i位足以容纳M,也即若M = 10 011,那么j和i之间至少可容纳5个位。例如,不可能出现j = 3和i = 2的情况, 5 | // 因为第3位和第2位之间放不下M。 6 | // 7 | // 示例1: 8 | // 输入:N = 10000000000, M = 10011, i = 2, j = 6 9 | // 输出:N = 10001001100 10 | // 示例2: 11 | // 输入: N = 0, M = 11111, i = 0, j = 4 12 | // 输出:N = 11111 13 | 14 | 15 | var insertBits = function(N, M, i, j) { 16 | let Nr = N.toString(2).split('').reverse(); 17 | let Mr = M.toString(2).split('').reverse(); 18 | for(let k = i; k <= j; k++){ 19 | Nr[k] = Mr[k - i] ? Mr[k - i]: '0'; 20 | } 21 | return ('0b' + Nr.reverse().join('')) / 1; 22 | }; 23 | // console.log(insertBits(1024, 19, 2, 6)); 24 | console.log(insertBits(2032243561, 25 | 10, 26 | 24, 27 | 29)); -------------------------------------------------------------------------------- /程序员面试金典/05.07-easy-.js: -------------------------------------------------------------------------------- 1 | //面试题 05.07. 配对交换 easy 2 | 3 | // 配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)。 4 | // 5 | // 示例1: 6 | // 输入:num = 2(或者0b10) 7 | // 输出 1 (或者 0b01) 8 | 9 | // 示例2: 10 | // 输入:num = 3 11 | // 输出:3 12 | 13 | // 提示: 14 | // num的范围在[0, 2^30 - 1]之间,不会发生整数溢出。 15 | 16 | 17 | var exchangeBits = function(num) { 18 | let binStr = num.toString(2); 19 | let arr = []; 20 | for (let i = binStr.length - 1; i >= 0; i = i - 2) { 21 | if (i - 1 >= 0){ 22 | arr.push(binStr[i-1]) 23 | arr.push(binStr[i]) 24 | } else { 25 | arr.push(0) // 题目没说,但是要补0 26 | arr.push(binStr[i]) 27 | } 28 | } 29 | return parseInt(arr.reverse().join(''),2); 30 | }; -------------------------------------------------------------------------------- /程序员面试金典/08.01-easy-三步问题.js: -------------------------------------------------------------------------------- 1 | 2 | //08.01. 三步问题 easy 3 | 4 | 5 | //三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。 6 | // 实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。 7 | // 8 | // 示例1: 9 | // 10 | // 输入:n = 3 11 | // 输出:4 12 | // 说明: 有四种走法 13 | // 示例2: 14 | // 15 | // 输入:n = 5 16 | // 输出:13 17 | // 提示: 18 | // n范围在[1, 1000000]之间 19 | 20 | 21 | /** 22 | * @param {number} n 23 | * @return {number} 24 | */ 25 | var waysToStep = function(n) { 26 | if(n === 1)return 1; 27 | if(n === 2)return 2; 28 | if(n === 3)return 4; 29 | let t3 = 1; 30 | let t2 = 2; 31 | let t1 = 4; 32 | for(let i = 4; i <= n; i++){ 33 | let t = (t1 + t2 + t3) % 1000000007; 34 | let tt = t1; 35 | let ttt = t2; 36 | t1 = t; 37 | t2 = tt; 38 | t3 = ttt; 39 | } 40 | return t1; 41 | }; -------------------------------------------------------------------------------- /程序员面试金典/08.03-easy-魔术索引.js: -------------------------------------------------------------------------------- 1 | 2 | // 08.03. 魔术索引 easy 3 | 4 | // 魔术索引。 在数组A[0...n-1]中,有所谓的魔术索引,满足条件A[i] = i。 5 | // 给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。 6 | // 7 | // 示例1: 8 | // 输入:nums = [0, 2, 3, 4, 5] 9 | // 输出:0 10 | // 说明: 0下标的元素为0 11 | // 示例2: 12 | // 输入:nums = [1, 1, 1] 13 | // 输出:1 14 | // 提示: 15 | // nums长度在[1, 1000000]之间 16 | // 17 | 18 | 19 | //面试题 08.03. 魔术索引 20 | var findMagicIndex = function(nums) { 21 | if (!nums.length) return -1; 22 | for(let i = 0; i < nums.length; i++){ 23 | if (nums[i] === i){ 24 | return i; 25 | } 26 | } 27 | return -1; 28 | }; -------------------------------------------------------------------------------- /程序员面试金典/08.07-medium-无重复字符串的排列组合.js: -------------------------------------------------------------------------------- 1 | // 面试题 08.07. 无重复字符串的排列组合 medium 2 | 3 | // 无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。 4 | // 5 | // 示例1: 6 | // 输入:S = "qwe" 7 | // 输出:["qwe", "qew", "wqe", "weq", "ewq", "eqw"] 8 | // 示例2: 9 | // 输入:S = "ab" 10 | // 输出:["ab", "ba"] 11 | // 提示: 12 | // 字符都是英文字母。 13 | // 字符串长度在[1, 9]之间。 14 | 15 | var permutation = function(S) { 16 | if (!S.length) return []; 17 | let result = []; 18 | let curPath = []; 19 | let dfs = (arr) => { 20 | if (curPath.length === S.length){ 21 | result.push(curPath.join('')); 22 | return; 23 | } 24 | for(let i = 0; i < arr.length; i++){ 25 | if (curPath.indexOf(arr[i]) !== -1){ 26 | continue; 27 | } 28 | curPath.push(arr[i]); 29 | dfs(arr); 30 | curPath.pop(); 31 | } 32 | }; 33 | dfs(S); 34 | return result; 35 | }; -------------------------------------------------------------------------------- /程序员面试金典/10.01-easy-合并排序的数组.js: -------------------------------------------------------------------------------- 1 | // 面试题 10.01. 合并排序的数组 2 | 3 | //给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。 4 | // 5 | // 初始化 A 和 B 的元素数量分别为 m 和 n。 6 | // 7 | // 示例: 8 | // 9 | // 输入: 10 | // A = [1,2,3,0,0,0], m = 3 11 | // B = [2,5,6], n = 3 12 | // 13 | // 输出: [1,2,2,3,5,6] 14 | // 说明: 15 | // 16 | // A.length == n + m 17 | 18 | 19 | var merge = function(A, m, B, n) { 20 | // 倒着来排,从大到小排 21 | let i = m -1; 22 | let j = n -1; 23 | let k = m + n - 1; // A的缓冲空间指针 24 | while(i !== -1 && j !== -1){ 25 | if (A[i] > B[j]){ 26 | A[k] = A[i]; 27 | i--; 28 | }else{ 29 | A[k] = B[j]; 30 | j--; 31 | } 32 | k--; 33 | } 34 | // 说明A排完了,B的剩余部分继续填到A里面 35 | if (i === -1 && j !== -1){ 36 | while(j !== -1){ 37 | A[k] = B[j]; 38 | k--; 39 | j--; 40 | } 41 | } 42 | return A; 43 | }; -------------------------------------------------------------------------------- /程序员面试金典/10.05-easy-稀疏数组搜索.js: -------------------------------------------------------------------------------- 1 | // 面试题 10.05. 稀疏数组搜索 easy 2 | 3 | // 稀疏数组搜索。有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置。 4 | // 5 | // 示例1: 6 | // 7 | // 输入: words = ["at", "", "", "", "ball", "", "", "car", "", "","dad", "", ""], s = "ta" 8 | // 输出:-1 9 | // 说明: 不存在返回-1。 10 | 11 | // 示例2: 12 | // 输入:words = ["at", "", "", "", "ball", "", "", "car", "", "","dad", "", ""], s = "ball" 13 | // 输出:4 14 | 15 | // 提示: 16 | // words的长度在[1, 1000000]之间 17 | 18 | var findString = function(words, s) { 19 | // 因为是排好序的字符串,按理应该用二分 20 | let hash = {}; 21 | for(let i = 0; i < words.length; i++){ 22 | hash[words[i]] = i; 23 | } 24 | return hash[s] >= 0 ? hash[s]: -1; 25 | }; -------------------------------------------------------------------------------- /程序员面试金典/16.01-medium-交换数字.js: -------------------------------------------------------------------------------- 1 | 2 | // 编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。 3 | // 4 | // 示例: 5 | // 6 | // 输入: numbers = [1,2] 7 | // 输出: [2,1] 8 | // 提示: 9 | // 10 | // numbers.length == 2 11 | 12 | // medium 13 | var swapNumbers = function(numbers) { 14 | numbers[1] = numbers[0] + numbers[1]; 15 | numbers[0] = numbers[1] - numbers[0]; 16 | numbers[1] = numbers[1] - numbers[0]; 17 | return numbers; 18 | }; 19 | -------------------------------------------------------------------------------- /程序员面试金典/16.11-easy-跳水板.js: -------------------------------------------------------------------------------- 1 | 2 | // 16.11. 跳水板 easy 3 | 4 | // 你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。 5 | // 你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。 6 | // 返回的长度需要从小到大排列。 7 | // 8 | // 示例: 9 | // 输入: 10 | // shorter = 1 11 | // longer = 2 12 | // k = 3 13 | // 输出: {3,4,5,6} 14 | // 提示: 15 | // 0 < shorter <= longer 16 | // 0 <= k <= 100000 17 | 18 | /** 19 | * @param {number} shorter 20 | * @param {number} longer 21 | * @param {number} k 22 | * @return {number[]} 23 | */ 24 | var divingBoard = function(shorter, longer, k) { 25 | if(k === 0)return [] 26 | let res = [] 27 | // 短的可以用0-k次 28 | for(let i = k; i >=0; i--){ 29 | // 那么长的可以用k-0次 30 | let time = k - i; 31 | let cnt = shorter * i + time * longer; 32 | if(res.indexOf(cnt) === -1){ 33 | res.push(cnt); 34 | } 35 | } 36 | return res; 37 | }; -------------------------------------------------------------------------------- /程序员面试金典/16.17-easy-连续数列.js: -------------------------------------------------------------------------------- 1 | 2 | // 16.17. 连续数列 easy 3 | 4 | // 给定一个整数数组,找出总和最大的连续数列,并返回总和。 5 | // 6 | // 示例: 7 | // 输入: [-2,1,-3,4,-1,2,1,-5,4] 8 | // 输出: 6 9 | // 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 10 | // 进阶: 11 | // 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 12 | 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number} 17 | */ 18 | var maxSubArray = function(nums) { 19 | if (!nums.length) return 0; 20 | let l = 0, r = 0; // 双指针 21 | let max = nums[0]; 22 | let cur = max; 23 | while(l <= r && r <= nums.length - 1){ 24 | if (cur <= 0){ 25 | r++; 26 | l = r; 27 | max = Math.max(cur, max); 28 | cur = nums[r]; 29 | }else{ 30 | r++; 31 | max = Math.max(cur, max); 32 | cur += nums[r] 33 | } 34 | } 35 | return max; 36 | }; 37 | 38 | // console.log('111: ', maxSubArray([-2,1,-3,4,-1,2,1,-5,4])) -------------------------------------------------------------------------------- /程序员面试金典/16.21-medium-交换和.js: -------------------------------------------------------------------------------- 1 | 2 | //面试题 16.21. 交换和 3 | 4 | 5 | //给定两个整数数组,请交换一对数值(每个数组中取一个数值),使得两个数组所有元素的和相等。 6 | // 7 | // 返回一个数组,第一个元素是第一个数组中要交换的元素,第二个元素是第二个数组中要交换的元素。若有多个答案,返回任意一个均可。若无满足条件的数值,返回空数组。 8 | // 9 | // 示例: 10 | // 11 | // 输入: array1 = [4, 1, 2, 1, 1, 2], array2 = [3, 6, 3, 3] 12 | // 输出: [1, 3] 13 | // 示例: 14 | // 15 | // 输入: array1 = [1, 2, 3], array2 = [4, 5, 6] 16 | // 输出: [] 17 | // 提示: 18 | // 19 | // 1 <= array1.length, array2.length <= 100000 20 | 21 | 22 | var findSwapValues = function(array1, array2) { 23 | let s1 = array1.reduce((p, n) => { 24 | return p + n; 25 | }); 26 | let s2 = array2.reduce((p, n) => { 27 | return p + n; 28 | }); 29 | // 总和是奇数,没办法平分 30 | let avg = (s1 + s2) / 2; 31 | if(!Number.isInteger(avg))return []; 32 | 33 | let dif = (s1 - s2) / 2; 34 | for(let i = 0; i < array1.length; i++){ 35 | if (array2.indexOf(array1[i] - dif) >= 0){ 36 | return [array1[i], array1[i] - dif]; 37 | } 38 | } 39 | return []; 40 | }; -------------------------------------------------------------------------------- /程序员面试金典/17.10-easy-主要元素.js: -------------------------------------------------------------------------------- 1 | 2 | // 面试题 17.10. 主要元素 easy 3 | 4 | // 数组中占比超过一半的元素称之为主要元素。给定一个整数数组,找到它的主要元素。若没有,返回-1。 5 | // 6 | // 示例 1: 7 | // 输入:[1,2,5,9,5,9,5,5,5] 8 | // 输出:5 9 | //   10 | // 示例 2: 11 | // 输入:[3,2] 12 | // 输出:-1 13 | // 14 | // 示例 3: 15 | // 输入:[2,2,1,1,1,2,2] 16 | // 输出:2 17 | // 18 | // 说明: 19 | // 你有办法在时间复杂度为 O(N),空间复杂度为 O(1) 内完成吗? 20 | 21 | 22 | /** 23 | * @param {number[]} nums 24 | * @return {number} 25 | */ 26 | var majorityElement = function(nums) { 27 | let len = nums.length / 2; 28 | let h = {} 29 | for(let i = 0; i < nums.length; i++){ 30 | h[nums[i]] = ~~h[nums[i]] + 1; 31 | } 32 | for(let k in h){ 33 | if(h[k] > len){ 34 | return k; 35 | } 36 | } 37 | return -1; 38 | }; -------------------------------------------------------------------------------- /程序员面试金典/17.16-easy-按摩师.js: -------------------------------------------------------------------------------- 1 | 2 | // 面试题 17.16. 按摩师 easy 3 | 4 | // 一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。 5 | // 在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列, 6 | // 替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。 7 | // 注意:本题相对原题稍作改动 8 | // 9 | // 10 | // 示例 1: 11 | // 输入: [1,2,3,1] 12 | // 输出: 4 13 | // 解释: 选择 1 号预约和 3 号预约,总时长 = 1 + 3 = 4。 14 | // 示例 2: 15 | // 输入: [2,7,9,3,1] 16 | // 输出: 12 17 | // 解释: 选择 1 号预约、 3 号预约和 5 号预约,总时长 = 2 + 9 + 1 = 12。 18 | // 示例 3: 19 | // 输入: [2,1,4,5,3,1,1,3] 20 | // 输出: 12 21 | // 解释: 选择 1 号预约、 3 号预约、 5 号预约和 8 号预约,总时长 = 2 + 4 + 3 + 3 = 12。 22 | 23 | -------------------------------------------------------------------------------- /程序员面试金典/17.19-hard-消失的两个数字.js: -------------------------------------------------------------------------------- 1 | // 17.19 hard 消失的两个数字 2 | 3 | // 给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗? 4 | // 以任意顺序返回这两个数字均可。 5 | // 6 | // 示例 1: 7 | // 输入: [1] 8 | // 输出: [2,3] 9 | // 示例 2: 10 | // 输入: [2,3] 11 | // 输出: [1,4] 12 | // 提示: 13 | // nums.length <= 30000 14 | 15 | 16 | // 17.19 17 | let missingTwo = (nums) => { 18 | let oL = nums.length + 2; 19 | let hash = {}; 20 | for (let i = 1; i <= oL; i++){ 21 | hash[nums[i - 1]] = true; 22 | if(hash[i] === true)continue; 23 | hash[i] = false; 24 | } 25 | let res = []; 26 | for(let k in hash){ 27 | if(hash[k] === false){ 28 | res.push(k / 1); 29 | } 30 | } 31 | return res; 32 | } 33 | console.log(missingTwo([1,3,4,5,6,7,9])); -------------------------------------------------------------------------------- /趣味题/两个数表示三个数.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | let getC = (a, b) => { 4 | return (a + b) % 100 5 | } 6 | 7 | let getA = (b, c) => { 8 | return c > b ? c - b: c + 100 -b; 9 | } 10 | 11 | 12 | let l1 = [1,2,'?']; 13 | let l2 = [99,99, '?'] 14 | let l3 = [5,99, '?'] 15 | let l4 = ['?',2, 3] 16 | let l5 = ['?',99, 98] 17 | let l6 = ['?',99, 5] 18 | 19 | console.log(getC(1,2)) 20 | console.log(getC(99,99)) 21 | console.log(getC(5,99)) 22 | console.log(getA(2,3)) 23 | console.log(getA(99,98)) 24 | console.log(getA(99,5)) -------------------------------------------------------------------------------- /递归/1137-easy-第 N 个泰波那契数.js: -------------------------------------------------------------------------------- 1 | // 1137 easy 第 N 个泰波那契数 2 | 3 | // 泰波那契序列 Tn 定义如下:  4 | // T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2 5 | // 给你整数 n,请返回第 n 个泰波那契数 Tn 的值。 6 | //   7 | // 8 | // 示例 1: 9 | // 输入:n = 4 10 | // 输出:4 11 | // 解释: 12 | // T_3 = 0 + 1 + 1 = 2 13 | // T_4 = 1 + 1 + 2 = 4 14 | 15 | // 示例 2: 16 | // 输入:n = 25 17 | // 输出:1389537 18 | // 19 | // 提示: 20 | // 0 <= n <= 37 21 | // 答案保证是一个 32 位整数,即 answer <= 2^31 - 1。 22 | 23 | 24 | 25 | function tribonacci(n){ 26 | if (n === 0) return 0 27 | if(n === 2 || n === 1) return 1 28 | let preOne = 1 29 | let preTwo = 1 30 | let preThree = 0 31 | let result = 0 32 | for (let i = 3; i <= n; i++) { 33 | result = preOne + preTwo + preThree; 34 | preThree = preTwo 35 | preTwo = preOne 36 | preOne = result 37 | } 38 | return result 39 | } 40 | 41 | console.log(tribonacci(25)) -------------------------------------------------------------------------------- /递归/509-fibna.js: -------------------------------------------------------------------------------- 1 | // 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: 2 | // 3 | // F(0) = 0,   F(1) = 1 4 | // F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 5 | // 给定 N,计算 F(N)。 6 | // 7 | // 示例 1: 8 | // 输入:2 9 | // 输出:1 10 | // 解释:F(2) = F(1) + F(0) = 1 + 0 = 1. 11 | 12 | // 示例 2: 13 | // 输入:3 14 | // 输出:2 15 | // 解释:F(3) = F(2) + F(1) = 1 + 1 = 2. 16 | 17 | // 示例 3: 18 | // 输入:4 19 | // 输出:3 20 | // 解释:F(4) = F(3) + F(2) = 2 + 1 = 3. 21 | // 22 | // 提示: 23 | // 0 ≤ N ≤ 30 24 | 25 | function fib(n){ 26 | if (n === 0) return 0 27 | if(n === 2 || n === 1) return 1 28 | let preOne = 1 29 | let preTwo = 1 30 | let result = 0 31 | for (let i = 3; i <= n; i++) { 32 | result = preOne + preTwo 33 | preOne = preTwo 34 | preTwo = result 35 | } 36 | return result 37 | } 38 | 39 | console.log(fib(27)) -------------------------------------------------------------------------------- /链表/141-easy-环形链表.js: -------------------------------------------------------------------------------- 1 | // easy 141 环形链表 2 | 3 | 4 | // 给定一个链表,判断链表中是否有环。 5 | // 6 | // 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 7 | // 如果 pos 是 -1,则在该链表中没有环。 8 | 9 | 10 | /** 11 | * Definition for singly-linked list. 12 | * function ListNode(val) { 13 | * this.val = val; 14 | * this.next = null; 15 | * } 16 | */ 17 | 18 | /** 19 | * 快慢指针,如果能相遇,则是环内相遇。如果没环,是不会相遇的 20 | * @param {ListNode} head 21 | * @return {boolean} 22 | */ 23 | var hasCycle = function(head) { 24 | if(!head)return false; 25 | let fast = head, slow = head; 26 | while(fast){ 27 | fast = fast.next; 28 | slow = slow.next; 29 | if(fast) fast = fast.next; 30 | else return false; 31 | 32 | // 相遇了 33 | if(fast === slow){ 34 | return true; 35 | } 36 | } 37 | return false; 38 | }; -------------------------------------------------------------------------------- /链表/160-easy-相交链表.js: -------------------------------------------------------------------------------- 1 | // 160 easy 相交链表 2 | 3 | // 编写一个程序,找到两个单链表相交的起始节点。 4 | // 5 | // 如下面的两个链表: 6 | // 7 | // 8 | // 9 | // 在节点 c1 开始相交。 10 | 11 | /** 12 | * Definition for singly-linked list. 13 | * function ListNode(val) { 14 | * this.val = val; 15 | * this.next = null; 16 | * } 17 | */ 18 | 19 | /** 20 | * 思路清奇。双指针,同步快慢。走两个链表的距离。 21 | * @param {ListNode} headA 22 | * @param {ListNode} headB 23 | * @return {ListNode} 24 | */ 25 | var getIntersectionNode = function(headA, headB) { 26 | let p = headA, q = headB 27 | while(p!==q){ 28 | if(p) p = p.next; 29 | else p = headB; 30 | 31 | if(q) q = q.next; 32 | else q = headA 33 | } 34 | return p; 35 | }; -------------------------------------------------------------------------------- /链表/203-easy-移除链表元素.js: -------------------------------------------------------------------------------- 1 | // 203 easy 移除链表元素 2 | 3 | // 删除链表中等于给定值 val 的所有节点。 4 | // 5 | // 示例: 6 | // 输入: 1->2->6->3->4->5->6, val = 6 7 | // 输出: 1->2->3->4->5 8 | 9 | /** 10 | * Definition for singly-linked list. 11 | * function ListNode(val) { 12 | * this.val = val; 13 | * this.next = null; 14 | * } 15 | */ 16 | /** 17 | * @param {ListNode} head 18 | * @param {number} val 19 | * @return {ListNode} 20 | */ 21 | var removeElements = function(head, val) { 22 | if(!head)return head; 23 | 24 | let vHead = new ListNode() 25 | vHead.next = head; 26 | 27 | let curNode = vHead 28 | while(curNode.next){ 29 | if(curNode.next.val === val){ 30 | if(curNode.next.next){ 31 | // 没到链表结尾 32 | curNode.next = curNode.next.next; 33 | }else{ 34 | // 到链表结尾了 35 | curNode.next = null 36 | } 37 | 38 | }else{ 39 | curNode = curNode.next; 40 | } 41 | } 42 | return vHead.next; 43 | }; -------------------------------------------------------------------------------- /链表/206-easy-反转链表.js: -------------------------------------------------------------------------------- 1 | // 206 easy 反转链表 2 | 3 | // 反转一个单链表。 4 | // 5 | // 示例: 6 | // 7 | // 输入: 1->2->3->4->5->NULL 8 | // 输出: 5->4->3->2->1->NULL 9 | // 进阶: 10 | // 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? 11 | // 12 | 13 | 14 | /** 15 | * @param {ListNode} head 16 | * @return {ListNode} 17 | */ 18 | var reverseList = function(head) { 19 | if(!head) return head 20 | let arr = [] 21 | let curNode = head; 22 | while(curNode){ 23 | arr.push(curNode.val) 24 | curNode = curNode.next 25 | } 26 | head = new ListNode(arr.splice([arr.length - 1], 1)) 27 | let cNode = head; 28 | while(arr.length){ 29 | cNode.next = new ListNode(arr.splice(arr.length - 1, 1)) 30 | cNode = cNode.next; 31 | } 32 | return head; 33 | }; -------------------------------------------------------------------------------- /链表/237-easy-删除链表中的节点.js: -------------------------------------------------------------------------------- 1 | // 237 easy 删除链表中的节点 2 | 3 | // 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 4 | // 5 | // 现有一个链表 -- head = [4,5,1,9],它可以表示为: 6 | // 7 | // 8 | // 9 | // 10 | // 11 | // 示例 1: 12 | // 输入: head = [4,5,1,9], node = 5 13 | // 输出: [4,1,9] 14 | // 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 15 | 16 | // 示例 2: 17 | // 输入: head = [4,5,1,9], node = 1 18 | // 输出: [4,5,9] 19 | // 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9. 20 | // 21 | // 说明: 22 | // 链表至少包含两个节点。 23 | // 链表中所有节点的值都是唯一的。 24 | // 给定的节点为非末尾节点并且一定是链表中的一个有效节点。 25 | // 不要从你的函数中返回任何结果。 26 | 27 | 28 | /** 29 | * Definition for singly-linked list. 30 | * function ListNode(val) { 31 | * this.val = val; 32 | * this.next = null; 33 | * } 34 | */ 35 | /** 36 | * 将要删的节点伪装成下一个节点,删掉下一个节点 37 | * @param {ListNode} node 38 | * @return {void} Do not return anything, modify node in-place instead. 39 | */ 40 | var deleteNode = function(node) { 41 | node.val = node.next.val; 42 | node.next = node.next.next; 43 | }; -------------------------------------------------------------------------------- /链表/24-medium-两两交换链表中的节点.js: -------------------------------------------------------------------------------- 1 | // 24 medium 两两交换链表中的节点 2 | 3 | // 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 4 | // 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 5 | // 6 | // 示例: 7 | // 给定 1->2->3->4, 你应该返回 2->1->4->3. 8 | 9 | 10 | /** 11 | * Definition for singly-linked list. 12 | * function ListNode(val) { 13 | * this.val = val; 14 | * this.next = null; 15 | * } 16 | */ 17 | /** 18 | * @param {ListNode} head 19 | * @return {ListNode} 20 | */ 21 | var swapPairs = function(head) { 22 | // 虚拟头节点 23 | let vHead = new ListNode(); 24 | vHead.next = head; 25 | 26 | let curNode = vHead; 27 | while(curNode.next && curNode.next.next){ 28 | let a = curNode.next; 29 | let b = a.next; 30 | curNode.next = b; 31 | a.next = b.next; 32 | b.next = a; 33 | 34 | // 向后推两个节点 35 | curNode = curNode.next.next; 36 | } 37 | return vHead.next; 38 | }; -------------------------------------------------------------------------------- /链表/5283-easy-二进制链表转整数.js: -------------------------------------------------------------------------------- 1 | // 5283 easy 二进制链表转整数 2 | 3 | //给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。 4 | // 请你返回该链表所表示数字的 十进制值 。 5 | // 6 | 7 | // 输入:head = [1,0,1] 8 | // 输出:5 9 | // 解释:二进制数 (101) 转化为十进制数 (5) 10 | 11 | /** 12 | * Definition for singly-linked list. 13 | * function ListNode(val) { 14 | * this.val = val; 15 | * this.next = null; 16 | * } 17 | */ 18 | /** 19 | * @param {ListNode} head 20 | * @return {number} 21 | */ 22 | var getDecimalValue = function(head) { 23 | if(!head)return 0; 24 | let str = ''; 25 | let node = head 26 | while(true){ 27 | if (!node) return parseInt(str, 2); 28 | str += node.val; 29 | node = node.next; 30 | } 31 | }; -------------------------------------------------------------------------------- /链表题目.md: -------------------------------------------------------------------------------- 1 | ## 链表 2 | 3 | * 2 medium 两数相加 4 | * 19 medium 删除链表的倒数第N个节点 5 | * 21 easy 合并两个有序链表 6 | * 24 medium 两两交换链表中的节点 7 | * 61 medium 旋转链表 8 | * 82 medium 删除排序链表中的重复元素2 9 | * 83 easy 删除排序链表中的重复元素 10 | * 141 easy 环形链表 11 | * 142 medium 环形链表2 12 | * 160 easy 相交链表 13 | * 203 easy 移除链表元素 14 | * 206 easy 反转链表 15 | * 237 easy 删除链表中的节点 16 | * 445 medium 两数相加2 17 | * 707 easy 设计链表 18 | * 817 medium 链表组件 19 | * 1019 medium 链表中的下一个更大节点 20 | * 5283 easy 二进制链表转整数 --------------------------------------------------------------------------------