问题:两数之和 问题描述:
1 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
1 2 3 输入:nums = [2, 7, 11, 15], target = 9 输出:[0, 1] 解释:nums[0] + nums[1] = 2 + 7 = 9
解法:
1 2 3 4 5 6 7 8 9 var twoSum = function (nums, target ){ let hash = {}; for (let i=0 ;i<nums.length ;i++){ if (hash[target-nums[i]] !== undefined ) return [i, hash[target-nums[i]]]; hash[nums[i]] = i; } return []; }
问题:三数之和 问题描述:
1 2 3 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 注意: 答案中不可以包含重复的三元组。
示例:
1 2 3 输入:nums = [-1, 0, 1, 2, -1, -4] 输出:[ [-1, 0, 1], [-1, -1, 2] ] //与两数相加的例子不同,此处只要返回数字,而两数相加需要返回索引,所以两数相加不适合用双指针
解法图示(双指针):
细节 - 需要去重 ,不能有重复的三元组,但是三元组内的元素是可以重复的:
1 2 3 4 5 6 7 8 //应该的写法 if (i > 0 && nums[i] == nums[i - 1]) { continue; } //不应该这么操作:会把三元组中出现重复元素的情况直接pass掉 if (nums[i] == nums[i + 1]) { // 去重操作 continue; }
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var threeSum = function (nums ){ const res = [], len = nums.length ; nums.sort ((a, b )=> a-b); for (let i=0 ;i<len;i++){ let left = i+1 , right=len-1 ,iNum = nums[i]; if (iNum>0 ) return res; if (iNum===nums[i-1 ]) continue ; while (left<right){ let lNum = nums[left], rNum = nums[right], threeSum = nums[i]+lNum+rNum; if (threeSum<0 ) left++; else if (threeSum>0 ) right--; else { res.push ([iNum, lNum, rNum]); while (left<right&&nums[left]==nums[left+1 ]) ++left; while (left<right&&nums[right]==nums[right-1 ]) --right; } left++; right--; } } return res; }
相加 描述:
1 2 3 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
1 2 3 输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8](链表) 解释:342 + 465 = 807.
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var addTwoNumbers = function (l1, l2 ){ let head = null , tail = null ; let carry = 0 ; while (l1 || l2){ const n1 = l1?l1.val :0 ; const n2 = l2?l2.val :0 ; const sum = n1+n2+carry; if (!head) head = tail = new ListNode (sum%10 ); else { tail.next = new ListNode (sum%10 ); tail = tail.next ; } carry = Math .floor (sum/10 ); if (l1) l1 = l1.next ; if (l2) l2 = l2.next ; } if (carry>0 ) tail.next = new ListNode (carry); return head; }
无重复字符的最长子串 描述:
1 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
1 2 3 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var lengthOfLongestSubstring = function (s ) { let map = new Map (); let left = 0 ; let maxLen = 0 ; for (let i = 0 ; i < s.length ; i++) { let char = s[i]; if (map.has (char)) { left = Math .max (map.get (char) + 1 , left); } map.set (char, i); maxLen = Math .max (maxLen, i - left + 1 ); } return maxLen; }
寻找两个正序数组的中位数 描述:
1 2 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (m+n)) 。
示例:
1 2 3 输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 var findMedianSortedArrays = function (nums1, nums2 ) { let m = nums1.length ; let n = nums2.length ; let left = Math .floor ((m + n + 1 ) / 2 ); let right = Math .floor ((m + n + 2 ) / 2 ); return (findKth (nums1, 0 , nums2, 0 , left) + findKth (nums1, 0 , nums2, 0 , right)) / 2 ; }; var findKth = function (nums1, start1, nums2, start2, k ) { if (start1 >= nums1.length ) { return nums2[start2 + k - 1 ]; } if (start2 >= nums2.length ) { return nums1[start1 + k - 1 ]; } if (k === 1 ) { return Math .min (nums1[start1], nums2[start2]); } let midVal1 = (start1 + Math .floor (k / 2 ) - 1 < nums1.length ) ? nums1[start1 + Math .floor (k / 2 ) - 1 ] : Infinity ; let midVal2 = (start2 + Math .floor (k / 2 ) - 1 < nums2.length ) ? nums2[start2 + Math .floor (k / 2 ) - 1 ] : Infinity ; if (midVal1 < midVal2) { return findKth (nums1, start1 + Math .floor (k / 2 ), nums2, start2, k - Math .floor (k / 2 )); } else { return findKth (nums1, start1, nums2, start2 + Math .floor (k / 2 ), k - Math .floor (k / 2 )); } }
最长回文子串 描述:
1 给你一个字符串 s,找到 s 中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例:
1 2 3 输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var longestPalindrome = function (s ) { let n = s.length ; if (n < 2 ) return s; let dp = new Array (n).fill ([]).map (() => new Array (n)); for (let i = 0 ; i < n; i++) dp[i][i] = true ; let maxlen = 1 ; let begin = 0 ; for (let len = 2 ; len < n + 1 ; len++) { for (let i = 0 ; i < n; i++) { let j = len + i - 1 ; if (j >= n) break ; if (s[i] !== s[j]) dp[i][j] = false ; else { if (j - i < 3 ) dp[i][j] = true ; else dp[i][j] = dp[i + 1 ][j - 1 ]; } if (dp[i][j] && (j - i + 1 > maxlen)) { maxlen = j - i + 1 ; begin = i; } } } return s.substring (begin, begin + maxlen); };
盛最多水的容器 描述:
1 2 3 4 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不能倾斜容器。
示例:
1 2 3 输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var maxArea = function (height ) { let size = height.length ; let left = 0 , right = size - 1 ; let ans = 0 ; while (left < right) { ans = Math .max (ans, (right - left) * Math .min (height[left], height[right])); if (height[left] > height[right]) { right--; } else { left++; } } return ans; }
电话号码的字母组合 描述:
1 2 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
1 2 输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var letterCombinations = function (digits ) { const k = digits.length ; const map = ["" , "" , "abc" , "def" , "ghi" , "jkl" , "mno" , "pqrs" , "tuv" , "wxyz" ]; if (k === 0 ) { return []; } if (k === 1 ) { return map[digits].split ('' ); } let res = [], path = []; function backtracking (digits, k, startIndex ) { if (path.length === k) { res.push (path.join ("" )); return ; } for (const v of map[digits[startIndex]]) { path.push (v); backtracking (digits, k, startIndex + 1 ); path.pop (v); } } backtracking (digits, k, 0 ); return res; }
删除链表的倒数第 N 个结点 描述:
1 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
1 2 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var removeNthFromEnd = function (head, n ) { let slow = head, fast = head; while (n-- && fast !== null ) { fast = fast.next ; } if (fast === null ) { return head.next ; } while (fast.next !== null ) { fast = fast.next ; slow = slow.next ; } slow.next = slow.next .next ; return head; }
有效的括号 描述:
1 2 3 4 5 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 有效字符串需满足: -左括号必须用相同类型的右括号闭合。 -左括号必须以正确的顺序闭合。 -每个右括号都有一个对应的相同类型的左括号。
示例:
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var isValid = function (s ) { let map = { '(' : ")" , "[" : "]" , "{" : "}" }; if (s.length % 2 ) { return false ; } let stack = []; for (let i = 0 ; i < s.length ; i++) { if (Object .keys (map).includes (s[i])) { stack.push (s[i]); } else { if (stack.length === 0 ) { return false ; } const top = stack.pop (); if (map[top] !== s[i]) { return false ; } } } return stack.length === 0 ; };
合并两个有序链表 描述:
1 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
1 2 输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var mergeTwoLists = function (l1, l2 ){ const prehead = new ListNode (-1 ); let prev = prehead; while (l1 && l2){ if (l1.val < l2.val ){ prev.next = l1; l1 = l1.next ; }else { prev.next = l2; l2 = l2.next ; } prev = prev.next ; } prev.next = l1 ? l1 : l2; return prehead.next ; }
合并K个有序链表 解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 var mergeKLists = function (lists ) { if (lists.length === 0 ) { return null ; } let ans = lists[0 ]; for (let i = 1 ; i < lists.length ; i++) { ans = mergeTwoLists (ans, lists[i]); } return ans; }; var mergeTwoLists = function (l1, l2 ) { const prehead = new ListNode (-1 ); let prev = prehead; while (l1 && l2) { if (l1.val < l2.val ) { prev.next = l1; l1 = l1.next ; } else { prev.next = l2; l2 = l2.next ; } prev = prev.next ; } prev.next = l1 ? l1 : l2; return prehead.next ; } var mergeKLists = function (lists ) { return merge (lists, 0 , lists.length - 1 ); } var merge = function (lists, l, r ) { if (l === r) { return lists[l]; } if (l > r) { return null ; } const mid = Math .floor ((l + r) / 2 ); return mergeTwoLists (merge (lists, l, mid), merge (lists, mid + 1 , r)); }
下一个排列 描述:
1 2 3 4 5 6 7 8 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。 给你一个整数数组 nums ,找出 nums 的下一个排列。 必须 原地 修改,只允许使用额外常数空间。
示例:
1 2 输入:nums = [1,2,3] 输出:[1,3,2]
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 var nextPermutation = function (nums ) { if (nums.length <= 1 ){ return ; } let i = nums.length - 2 , j = nums.length - 1 , k = nums.length - 1 ; while (i>=0 && nums[i] >= nums[j]){ i--; j--; } if (i>=0 ){ while (nums[i] >= nums[k]){ k--; } [nums[i], nums[k]] = [nums[k], nums[i]]; } i = j; j = nums.length - 1 ; while (i < j){ [nums[i], nums[j]] = [nums[j], nums[i]]; i++; j--; } }
最长有效括号 描述:
1 给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例:
1 2 3 输入:s = "(()" 输出:2 解释:最长有效括号子串是 "()"
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var longestValidParentheses = function (s ) { let n = s.length ; let dp = new Array (n).fill (0 ); let maxLen = 0 ; for (let i = 1 ; i < n; i++) { if (s[i] === ')' ) { if (s[i - 1 ] === '(' ) { dp[i] = 2 ; if (i - 2 >= 0 ) { dp[i] = dp[i - 2 ] + 2 ; } } else if (dp[i - 1 ] > 0 ) { let lastIndex = i - dp[i - 1 ] - 1 ; if (lastIndex >= 0 && s[lastIndex] === '(' ) { dp[i] = dp[i - 1 ] + 2 ; if (lastIndex - 1 >= 0 ) { dp[i] = dp[i] + dp[lastIndex - 1 ]; } } } } maxLen = Math .max (maxLen, dp[i]); } return maxLen; }
搜索旋转排序数组 描述:
1 2 3 4 整数数组 nums 按升序排列,数组中的值互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。 给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。 你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
示例:
1 2 输入:nums = [4,5,6,7,0,1,2], target = 0 输出:4
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 var search = function (nums, target ) { let n = nums.length ; if (!n) { return -1 ; } if (n === 1 ) { return nums[0 ] === target ? 0 : -1 ; } let left = 0 , right = nums.length - 1 ; while (left <= right) { let mid = Math .floor ((left + right) / 2 ); if (nums[mid] === target) { return mid; } if (nums[0 ] <= nums[mid]) { if (nums[0 ] <= target && target < nums[mid]) { right = mid - 1 ; } else { left = mid + 1 ; } } else { if (nums[mid] < target && target <= nums[n - 1 ]) { left = mid + 1 ; } else { right = mid - 1 ; } } } return -1 ; }
在排序数组中查找元素的第一个和最后一个位置 描述:
1 2 3 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例:
1 2 输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4]
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var searchRange = function (nums, target ){ let left = search (nums, target); let right = search (nums, target+1 ); if (left === nums.length || nums[left] !== target){ return [-1 , -1 ]; } return [left, right-1 ]; } var search = function (nums, target ){ let left = 0 , right = nums.length ; while (left < right){ let mid = Math .floor ((left+right)/2 ); if (nums[mid] >= target){ right = mid; }else { left = mid + 1 ; } } return left; }
组合总和 描述:
1 2 3 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例:
1 2 3 4 5 6 输入:candidates = [2,3,6,7], target = 7 输出:[[2,2,3],[7]] 解释: 2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合。
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 var combinationSum = function (candidates, target ) { const res = []; const path = []; candidates.sort ((a, b ) => a - b); function backtracking (startIndex, sum ) { if (sum === target) { res.push (Array .from (path)); return ; } for (let i = startIndex; i < candidates.length ; i++) { const n = candidates[i]; if (n > target - sum) { break ; } path.push (n); sum += n; backtracking (i, sum); path.pop (); sum -= n; } } backtracking (0 , 0 ); return res; } var sum = function (candidates, target ){ const res = []; const path = []; candidates.sort ((a, b )=> a-b); function backtracking (startIndex, sum ){ if (sum === target){ res.push (Array .from (path)); return ; } if (sum > target){ return ; } for (let i=startIndex;i<candidates.length ;i++){ if (i>startIndex && candidates[i] === candidates[i-1 ]) continue ; const n = candidates[i]; if (n > target - sum){ break ; } sum += n; path.push (n); backtracking (i+1 , sum); path.pop (); sum -= n; } } backtracking (0 , 0 ); return res; } let res = combinationSum ([2 , 2 , 2 , 2 ], 6 );console .log (res);
接雨水 描述:
1 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例:
1 2 3 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 var trap = function (height ) { let len = height.length ; if (len < 2 ) { return 0 ; } let stack = [0 ]; let sum = 0 ; let lastIndex = 1 ; for (let i = 1 ; i < len; i++) { if (height[i] < height[stack[lastIndex]]) { stack.push (i); lastIndex++; } else if (height[i] === height[stack[lastIndex]]) { stack[lastIndex] = i; } else { while (stack.length && height[i] > height[stack[lastIndex]]) { let mid = stack[lastIndex]; lastIndex--; stack.pop (); if (stack.length ) { let h = Math .min (height[stack[lastIndex]], height[i]) - height[mid]; let w = i - stack[lastIndex] - 1 ; sum += h * w; } } stack.push (i); lastIndex++; } } return sum; }
全排列 解法:
1 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例:
1 2 输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
描述:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var permute = function (nums ) { let res = []; let path = []; function backtracking (used ) { if (path.length === nums.length ) { res.push (Array .from (path)); return ; } for (let i = 0 ; i < nums.length ; i++) { if (used[i]) { continue ; } path.push (nums[i]); used[i] = true ; backtracking (used); used[i] = false ; path.pop (); } } backtracking ([]); return res; }
旋转图像 描述:
1 2 给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例:
1 2 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8,5,2],[9,6,3]]
字母异位词分组 描述:
1 2 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例:
1 2 输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"] 输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 var groupAnagrams = function (strs ) { const map = new Map (); for (let str of strs) { let arr = Array .from (str); arr.sort (); let key = arr.toString (); let list = map.get (key) ? map.get (key) : []; list.push (str); map.set (key, list); } return Array .from (map.values ()); } var groupAnagrams = function (strs ) { const map = {}; for (let s of strs) { const count = new Array (26 ).fill (0 ); for (let c of s) { count[c.charCodeAt () - 'a' .charCodeAt ()]++; } map[count] ? map[count].push (s) : map[count] = [s]; } return Object .values (map); }
最大子数组和 描述:
1 2 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。
示例:
1 2 3 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var maxSubArray = function (nums ) { let dp = new Array (nums.length ); dp[0 ] = nums[0 ]; let res = nums[0 ]; for (let i = 1 ; i < nums.length ; i++) { if (dp[i - 1 ] < 0 ) { dp[i] = nums[i]; } else { dp[i] = nums[i] + dp[i - 1 ]; } res = Math .max (res, dp[i]); } return res; }