callqh / algorithm Goto Github PK
View Code? Open in Web Editor NEW记录刷题的过程,一直坚持的事情回头看肯定很酷
记录刷题的过程,一直坚持的事情回头看肯定很酷
给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/volume-of-histogram-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
(黑+蓝) - 黑 = 蓝
黑+蓝) - 黑 = 蓝
/**
* @param {number[]} height
* @return {number}
*/
var trap = function (height) {
// 定义左指针
let left = 0;
// 定义右指针
let right = height.length - 1;
// 初始化层数
let heigh = 1;
// 初始化所有层数的块数之和
let sum = 0;
while (left <= right) {
// 判断左指针对应的数据是否小于层级,如果小于层级的话,就移动左指针
// 这里需要注意,如果指针对应的数比层级大,指针是不会进行移动的,直到当前的数小于层级为止
// 所以即时第一个数是2,我们初始层级是1,那么因为2是由两个黑色块堆积出来的,所以在一层肯定也有一个块
// 所以这时候依然要计算,直到碰到层级大于2再进行移动
while (left <= right && height[left] < heigh) {
left++;
}
// 判断右指针的数是否小于层级
while (left <= right && height[right] < heigh) {
right--;
}
// 更新层数的块数之和
sum += right - left + 1;
// 更新层级
heigh += 1;
}
// 遍历所有黑色块
let blackSum = 0;
height.forEach((n) => (blackSum += n));
// 返回最终结果 (黑+蓝) - 黑
return sum - blackSum;
};
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var middleNode = function(head) {
let p1 = head, p2 = head;
while(p2!==null&&p2.next!==null){
p1 = p1.next;
p2 = p2.next.next;
}
return p1;
};
通常,正整数 n 的阶乘是所有小于或等于 n 的正整数的乘积。例如,factorial(10) = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1。
相反,我们设计了一个笨阶乘 clumsy:在整数的递减序列中,我们以一个固定顺序的操作符序列来依次替换原有的乘法操作>符:乘法(*),除法(/),加法(+)和减法(-)。
例如,clumsy(10) = 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1。然而,这些运算仍然使用通常的算术运算顺序:我们在任何加、减步骤>之前执行所有的乘法和除法步骤,并且按从左到右处理乘法和除法步骤。
另外,我们使用的除法是地板除法(floor division),所以 10 * 9 / 8 等于 11。这保证结果是一个整数。
实现上面定义的笨函数:给定一个整数 N,它返回 N 的笨阶乘。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/clumsy-factorial
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
下标模4
的值来判断进行何种操作/**
* @param {number} N
* @return {number}
*/
var clumsy = function (N) {
// 创建栈,并将第一个数字入栈
const stack = [N];
// 从第二个数字的下标开始计算对应的操作符
const index = 0;
N--;
// 遍历
while (N > 0) {
if (index % 4 === 0) {
stack.push(stack.pop() * N);
} else if (index % 4 === 1) {
const n = stack.pop();
// 这里需要注意,因为我们的值需要向下取整,所以要判断相除的结果是正数还是负数
stack.push(n / N > 0 ? Math.floor(n / N) : Math.ceil(n / N));
} else if (index % 4 === 2) {
// 加操作,直接入栈
stack.push(N);
} else {
// 减操作,将数字的相反数入栈
stack.push(-N);
}
}
// 遍历完成之后就遍历栈结构进行相加
let res = 0;
stack.forEach((n) => (res += n));
return res;
};
LDR
的形式进行遍历就好了/**
* @param {TreeNode} root
* @return {number[]}
*/
var preorderTraversal = function (root) {
// 创建接收结果的数组
const ret = [];
// 递归函数
const innerPreorder = (root) => {
// 节点为空直接返回
if (!root) return;
// 将根节点的值放入数组中
ret.push(root.val);
// 递归遍历左节点
innerPreorder(root.left);
// 递归遍历右节点
innerPreorder(root.right);
};
// 调用递归
innerPreorder(root);
// 返回结果
return ret;
};
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
let p = head;
let prev = null;
while(p!==null){
const tmp = p.next;
p.next = prev;
prev = p;
p = tmp;
}
return prev;
};
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
let dumy = new ListNode(-1)
dumy.next = head;
let p1=dumy,p2=dumy;
while(n!==0){
n--;
p2=p2.next;
}
while(p2.next!==null){
p1 = p1.next;
p2 = p2.next
}
p1.next = p1.next.next;
return dumy.next;
};
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba"
输出: True
示例 2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-palindrome-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/**
* @param {string} s
* @return {boolean}
*/
var validPalindrome = function(s) {
let l = 0;
let r = s.length -1;
// 指针的值相同,缩小区间
while(l<r&&s[l]===s[r]){
l++;
r--;
}
// 遇到不同的就尝试分别跳过左侧或者右侧的值
// 验证跳过该值的区间是否符合回文特征
if(isPalindrome(l+1,r)) return true;
if(isPalindrome(l,r-1)) return true;
// 验证回文
function isPalindrome(l,r){
while(l<r){
if(s[l]!==s[r]) return false;
l++;
r--;
}
return true;
}
// 否则则返回false
return false;
};
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation
/**
* 判断当前字符是否为数字
* @param {string} token 判断该字符是否为标识符
* @returns boolean
*/
const isNumber = (token) => {
return !(token === "+" || token === "-" || token === "*" || token === "/");
};
/**
* @param {string[]} tokens
* @return {number}
*/
var evalRPN = function (tokens) {
const len = tokens.length;
// 创建栈
const stack = [];
// 遍历字符串
for (let i = 0; i < len; i++) {
const t = tokens[i];
// 判断是否为数字
if (isNumber(t)) {
// 是 - 入栈
stack.push(parseInt(t));
} else {
// 否 - 进行对应的标识符操作
const n2 = stack.pop();
const n1 = stack.pop();
if (t === "+") {
stack.push(n2 + n1);
} else if (t === "-") {
stack.push(n2 - n1);
} else if (t === "*") {
stack.push(n2 * n1);
} else {
stack.push(n2 / n1 > 0 ? Math.floor(n2 / n1) : Math.ceil(n2 / n1));
}
}
}
// 返回结果
return stack.pop();
};
给你两个有序整数数组 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]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-sorted-array
/**
* @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) {
let p1 = m - 1;
let p2 = n - 1;
let last = m + n -1;
while(p1 >=0 && p2>=0){
if(nums1[p1] > nums2[p2]){
nums1[last] = nums1[p1];
p1--
}else{
nums1[last] = nums2[p2]
p2--
}
last--;
}
// 如果第二个数组还有剩余元素没有进行比较,就逐个将元素放入数组1中
while(p2>=0){
nums1[last--] = nums2[p2--];
}
return nums1;
};
/**
* @param {number[][]} matrix
* @param {number} target
* @return {boolean}
*/
var searchMatrix = function(matrix, target) {
// 第一个二分搜索,查找出目标值可能所处的行数组
const binarySearch = (nums)=>{
let low = 0;
let height = nums.length - 1;
while(low < height){
let mid = Math.floor((low + height)/2);
if(nums[mid][0] > target){
height = mid - 1;
}else if(nums[mid][nums[mid].length - 1] < target){
low = mid + 1;
}else {
return low = mid;
}
}
return low
}
// 第二个二分搜索,对第一个搜索出的数组进行二分搜索
const binarySearchResult = (nums)=>{
let left = 0;
let right = nums.length - 1;
while(left <= right){
let mid = Math.floor((left+right)/2);
if(nums[mid] > target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else{
return true;
}
}
return false;
}
const index = binarySearch(matrix);
return binarySearchResult(matrix[index]);
};
坚持下去的事情,等过了一段时间回头看肯定觉得会很牛逼。
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
提示:
- 2 <= nums.length <= 103
- -109 <= nums[i] <= 109
- -109 <= target <= 109
- 只会存在一个有效答案
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function (nums, target) {
// 创建字典表
const m = new Map();
// 遍历数组
for (let i = 0; i < nums.length; i++) {
// 获取当前值
const n = nums[i];
// 获取需要的值,即当前值相加可以获得target的数字
const t = target - n;
// 如果有就返回对应下标数组
if (m.has(t)) {
return [m.get(t), i];
}
// 否则将当前值和下标放入字典
m.set(n, i);
}
};
假设数组的长度为 n:
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
let p1 = head;
let p2 = head;
for(let i = 0; i < k; i++){
p2 = p2.next;
}
while(p2!==null){
p2 = p2.next;
p1 = p1.next;
}
return p1;
};
给你一个整数数组 nums,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 50000
-50000 <= nums[i] <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-an-array
给你两个有序整数数组 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]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
109 <= nums1[i], nums2[i] <= 109
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-sorted-array
var isValidBST = function (root) {
// 中序遍历
const ret = [];
const inorder = root => {
if (!root) return [];
if (root.left) inorder(root.left);
ret.push(root.val);
if (root.right) inorder(root.right);
};
inorder(root);
// 判断中序遍历的结果是否为升序
let tmp = ret.pop();
while (ret.length) {
const n = ret.pop();
if (n >= tmp) return false;
tmp = n;
}
return true;
};
##复杂度
[ 最小值,上一个根节点的val ]
,右子树的根节点值应该是在[ 上一个根节点的val, 最大值 ]
-Infinity
Infinity
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isValidBST = function(root) {
const inner = (root,lower,upper)=>{
if(!root) return true;
// 判断当前的值是否处于当前的区间内 (小,大),注意需要是个开区间
if(root.val <= lower || root.val >= upper){
return false;
}
return inner(root.left,lower,root.val)&&inner(root.right,root.val,upper)
}
// 调用递归函数,初始化区间为+-无穷,保证树的第一个根节点始终在区间内
return inner(root,-Infinity,Infinity);
};
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:输入: "A man, a plan, a canal: Panama"
输出: true
示例 2:输入: "race a car"
输出: false来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-palindrome
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/**
* @param {string} s
* @return {boolean}
*/
var isPalindrome = function(s) {
let l = 0;
let r = s.length - 1;
const ans = s.toUpperCase();
while(l < r){
while(/[^A-Za-z0-9]/.test(ans[l])){
l++
}
while(/[^A-Za-z0-9]/.test(ans[r])) {
r--
}
if(l<r&&ans[l] !== ans[r]){
return false;
}
l++;
r--;
}
return true;
};
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
let fast = head,slow = head;
const dumy = new ListNode();
dumy.next = head;
while(fast!==null && fast.next!==null){
slow = slow.next;
fast = fast.next.next;
if(slow === fast) {
return true;
}
}
return false;
};
var levelOrder = function(root) {
if(!root) return [];
const q = [root];
const result = [];
let depth = 0;
while(q.length){
const size = q.length;
result[depth]=[];
for(let i =0;i<size;i++){
const node = q.shift();
result[depth].push(node.val);
if(node.left) q.push(node.left)
if(node.right) q.push(node.right)
}
depth++;
}
return result;
};
给你单链表的头节点 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function(list1, list2) {
let p1 = list1, p2 = list2;
let dumy = new ListNode(-1),root = dumy;
while(p1!=null&&p2!=null){
if(p1.val<p2.val){
dumy.next = p1;
p1=p1.next;
} else {
dumy.next = p2;
p2=p2.next;
}
dumy = dumy.next;
}
if(p1!=null) dumy.next = p1;
if(p2!=null) dumy.next = p2;
return root.next;
};
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
let p1 = headA, p2 = headB;
while(p1!==p2){
if(p1===null){
p1 = headB;
}else{
p1 = p1.next;
}
if(p2 === null){
p2 = headA;
}else {
p2 = p2.next;
}
}
return p1;
};
var inorderTraversal = function(root) {
const ret = [];
const inorder = root=>{
if(!root) return;
inorder(root.left);
ret.push(root.val);
inorder(root.right);
}
inorder(root)
return ret;
};
时间复杂度:o(n)n是树的深度,递归的时候需要维护一个递归栈
空间复杂度:o(n) n是树的深度
var inorderTraversal = function (root) {
if (!root) return [];
// 模拟栈
const stack = [];
// 结果数组
const ret = [];
// 指针
let p = root;
// 遍历栈
while (stack.length || p) {
// 将左右左节点入栈
while (p) {
stack.push(p);
p = p.left;
}
// 弹出栈顶
const d = stack.pop();
// 记录栈顶的值
ret.push(d.val);
// 将指针指向栈顶元素的右节点,在下一轮迭代的时候将右节点的所有子节点入栈
p = d.right;
}
// 返回结果
return ret;
};
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let fast = head,slow = head;
while(fast!==null&&fast.next!==null){
fast = fast.next.next;
slow = slow.next;
if(slow===fast){
break;
}
}
// 没有环
if(fast===null || fast.next===null){
return null;
}
slow = head;
while(slow!==fast){
slow = slow.next;
fast = fast.next;
}
return slow;
};
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} x
* @return {ListNode}
*/
var partition = function(head, x) {
let dumy1 = new ListNode(-1),p1 = dumy1;
let dumy2 = new ListNode(-2),p2 = dumy2;
let p = head;
while(p!==null){
if(p.val<x){
dumy1.next = p;
dumy1 = dumy1.next;
}else{
dumy2.next = p;
dumy2 = dumy2.next;
}
// 断开原链表中每个节点的next,防止出现循环链表
const tmp = p.next;
p.next = null;
p = tmp;
}
dumy1.next = p2.next;
return p1.next;
};
LRD
var postorderTraversal = function(root) {
const ret = [];
const postorder = root=>{
if(!root) return;
postorder(root.left);
postorder(root.right);
ret.push(root.val)
}
postorder(root)
return ret;
};
时间复杂度:o(n)
空间复杂度:o(n)
var postorderTraversal = function (root) {
if (!root) return [];
// 结果数组
const ret = [];
// 临时接受变形的前序遍历结果
const tmp = [];
// 模拟栈
const stack = [root];
// 遍历栈
while (stack.length) {
// 取出栈顶元素
const d = stack.pop();
// 压入根元素 D
tmp.push(d.val);
// 左节点入栈,因为要先执行右节点
if (d.left) stack.push(d.left);
// 右节点后入栈
if (d.right) stack.push(d.right);
}
// 经过上面遍历出来的 DRL的结果,我们这里输出为LRD
while (tmp.length) {
ret.push(tmp.pop());
}
// 返回结果
return ret;
};
快排整体采用的是分治的方法,分为三步实现:
q[l
]、数组右侧的值q[r]
、中间值q[(r+l)/2]
以及随机四种;<x
,右侧是>=x
;(难点)/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function(nums) {
quick_sort(nums,0,nums.length-1);
return nums;
};
function quick_sort(nums,left,right){
if(left>=right) return;
// 找到临界值,定义左右指针
let x = nums[left], i=left-1,j=right+1;
// 根据临界值划分区间
while(i<j){
do{i++}while(nums[i]<x);
do{j--}while(nums[j]>x);
if(i<j){
const tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
quick_sort(nums,left,j);
quick_sort(nums,j+1,right);
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.