5.8-字母异位词分组
题解:
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例 1:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
代码:
/**
* @param {string[]} strs
* @return {string[][]}
*/
var groupAnagrams = function(strs) {
let hash = new Map();
strs.forEach( str => {
let key = str.split('').sort((a,b)=>a.localeCompare(b)).join()
if(hash.has(key)){
let temp = hash.get(key);
temp.push(str)
hash.set(key, temp);
}else{
hash.set(key, [str]);
}
})
return [...hash.values()];
};
5.7-括号生成
题解:
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
代码:
/**
* @param {number} n
* @return {string[]}
*/
var generateParenthesis = function(n) {
let result = [];
function dfs(str,left,right){
if(left === 0 && right === 0) {
result.push(str);
return;
}
if(left>right) {
return;
}
if(left>0) {
dfs(str+'(',left-1,right)
}
if(right>0) {
dfs(str+')',left,right-1)
}
}
dfs("",n,n);
return result;
};
5.6-最接近的三数之和
题解:
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例 1:
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
代码:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var threeSumClosest = function(nums, target) {
nums.sort((a,b)=>a-b);
let sum = nums[0] + nums[1] + nums[2];
for(let m = 0; m<nums.length-2; m++) {
let i=m+1,j=nums.length-1;
while(i<j) {
let add = nums[i] + nums[j] + nums[m];
if(add === target) return add;
sum = Math.abs(add-target) < Math.abs(sum-target) ?
add : sum;
add < target ? i++ : j--;
}
}
return sum;
};
5.5-删除链表的倒数第N个节点
题解:
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例 1:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
代码:
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let preHead = new ListNode(0);
preHead.next = head
let p = preHead, q = preHead;
for(let i = 0; i < n; i++){
q = q.next;
}
while(q&&q.next){
q = q.next;
p = p.next;
}
p.next = p.next.next;
// console.log(head);
return preHead.next;
};
5.4-合并有序数组
题解:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
代码:
var threeSum = function(nums) {
nums.sort((a,b)=> a-b);
let start = 0, end = nums.length-1,result = [];
while(start < end) {
let rest = -nums[start]-nums[end];
for(let i=start+1;i<=end-1;i++){
if(nums[i]===rest){
result.push([nums[start],nums[i],nums[end]]);
console.log(i, [nums[start],nums[i],nums[end]]);
while(start<end && nums[start]==nums[start+1]) start++;
while(start<end && nums[end]==nums[end-1]) end--;
break;
}
}
nums[end-1] <= rest ? start++ : end--;
}
return result;
};
5.3-整数转罗马数字
题解:
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。。
示例 1:
输入: 3
输出: "III"
代码:
/**
* @param {number} num
* @return {string}
*/
var intToRoman = function(num) {
let map = [[1000,'M'],[900,'CM'],[500,'D'],[400,'CD'],[100,'C'],[90,'XC'],[50,'L'],[40,'XL'],[10,'X'],[9,'IX'],[5,'V'],[4,'IV'],[1,'I']];
let result = '', index = 0;
while (index < 13){
while(map[index][0]<=num){
num-=map[index][0];
result+=map[index][1]
}
index++;
}
return result;
};
4.29-字符串转整数
题解:
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
示例 1:
输入: "42"
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
因此无法执行有效的转换。
代码:
/**
* @param {string} str
* @return {number}
*/
var myAtoi = function(str) {
const num = parseInt(str);
if(isNaN(num)) return 0
else if(num<Math.pow(-2,31) || num>Math.pow(2,31)-1) return num < Math.pow(-2, 31) ? Math.pow(-2, 31) : Math.pow(2, 31) - 1;
else return num
};
4.28-合并有序数组
题解:
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例 1:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
代码:
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
// p1指向nums1最后一个数,p2指向nums2最后一个数,p指向排序后的数组最后一个数
let p1 = m-1, p2 = n-1, p = m + n -1;
while( (p1>=0) && (p2>=0) ){
nums1[p--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--];
}
for(let i=0; i<p2+1; i++){
nums1[i] = nums2[i];
}
return nums1;
};
4.26-有效的数独
题解:
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-sudoku
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例 1:
输入:
[
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
输出: true
代码:
/**
* @param {character[][]} board
* @return {boolean}
*/
var isValidSudoku = function(board) {
let rows = [[],[],[],[],[],[],[],[],[],],
columns = [[],[],[],[],[],[],[],[],[],],
boxes = [[],[],[],[],[],[],[],[],[],];
for(let i in board){
for(let j in board[i]){
let num = board[i][j];
if(num !== ".") {
let k = 3*Math.floor(i/3) + Math.floor(j/3);
if(arrayHasNum(rows[i],num)){
rows[i].push(num)
}else{
return false
}
if(arrayHasNum(columns[j],num)){
columns[j].push(num)
}else{
return false
}
if(arrayHasNum(boxes[k],num)){
boxes[k].push(num)
}else{
return false
}
}
}
};
return true;
};
function arrayHasNum(array, target) {
let flag = true;
for(let i in array){
if(array[i]===target) flag = false;
}
return flag;
}
4.25-全排列
题解:
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例 1:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
代码:
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permute = function(nums) {
let result = [];// 存放结果数组
let backtrack = (path) =>{
if(nums.length === path.length) result.push(path);
for(let n of nums){
if(!path.includes(n)){
path.push(n);
backtrack(path.slice());
path.pop();
}
}
}
backtrack([])
return result;
};
4.23-盛最多水的容器
题解:
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
示例 1:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
代码:
var maxArea = function(height) {
let i = 0; j = height.length-1;
let max = (j-i) * Math.min(height[i],height[j]);
while(i<j){
if(height[i]<=height[j]){ i++ }
else{ j-- }
let v = (j-i) * Math.min(height[i],height[j]);
max = Math.max(max,v);
}
return max;
};
4.22-Z 字形变换
题解:
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。
示例 1:
输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
代码:
/**
* @param {string} s
* @param {number} numRows
* @return {string}
*/
var convert = function(s, numRows) {
let flag = -1,temp=0,res=[],result="";
if(numRows==1) return s;
// 初始化结果数组
for(let i=0 ; i<numRows ; i++){
res[i] = '';
}
// 重组
for(let i of s){
if(temp == 0 || temp == numRows -1) flag = -flag;
res[temp] += i;
temp += flag;
}
for(let i of res){
result+=i;
}
return result
};
4.21-两数相加
题解:
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
代码:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
let add = 0;// add记录进位
let result = new ListNode(),cur = result;
while(l1||l2){
let n1 = l1.val ? l1.val : 0;
let n2 = l2.val ? l2.val : 0;
let num = n1+n2+add;// 暂存相加结果
add = num >= 10 ? 1 : 0;
num = num >= 10 ? num-10 : num;
cur.next = new ListNode(num);
cur = cur.next;
l1 = l1.next ? l1.next : 0;
l2 = l2.next ? l2.next : 0;
}
// 处理最高位进位情况
if(add>0){
cur.next = new ListNode(add);
}
return result.next;
};
4.19-最长回文字符串
题解:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。。
代码:
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function(s) {
let left = 0,right = 0,max = 1;
let start = 0;// 存储最长回文字符串指针
// 特殊判断
if(s.length < 2) return s;
for(let center = 0; center < s.length; center++){
let cur = s[center];// 当前字母
let len = 1;// 当前循环长度
left = center-1;right = center+1;
// 向左扩展,如果当前值和左边相等
while(s[left]==cur&&left>=0){
len++;
left--;
}
while(s[right]==cur&&right<s.length){
right++;
len++;
}
while(s[left]==s[right] && left>=0 && right<s.length){
left--;right++;len+=2;
}
if(len>max){
max = len;
start = left;
}
}
return s.substring(start+1,start+1+max);
};
4.18-无重复字符的最长子串
题解:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
思路:
-
设置一个滑动窗口“q”,记录没有重复的字符串
1.1 如果新的字母,窗口中没有,给窗口添加进新的字符串
1.2 如果新的字母是重复字母,裁剪窗口到新字母之后的位置
-
i为当前字母,cur为当前窗口长度,max为历史窗口最长的长度
-
以“wkew”为例:
3.1 i = w; q->"w"; cur->1; max->1
3.2 i = k; q->"wk"; cur->2; max->2
3.3 i = e; q->"wke"; cur->3; max->3
3.4 i = w; 这时候发现w已经出现过,q=“wkew”,因此需要裁剪窗口到w第一次出现之后: 即 q->"kew"; cur->3; max->3
代码:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
let q = ""; // 滑动队列
let cur = 0, max = 0;
for(let i of s){
if(q.indexOf(i)==-1){
q+=i;
max = Math.max(++cur,max)
}else{
q+=i;
q=q.slice(q.indexOf(i)+1);
cur = q.length;
}
}
return max;
};