2021.10.30
15:50
var reverseList = function(head) {
var prev = null;
var curr = head;
while(curr){
next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;
};
var numWays = function(n) {
let arr=[1,1,2]
if(n<=2){
return arr[n]
}else{
for(let i=arr.length;i<=n;i++){
arr[i]=(arr[i-1]+arr[i-2])%1000000007
}
}
return arr[n]
};
//解题思路:设置快慢指针,若快指针可以追上慢指针,说明有环
var hasCycle = function(head) {
if(head === null || head.next === null) {
return false;
}
var slow=head;
var fast=head.next;
while(fast&&fast.next){
if(fast==slow){
return true
}
fast=fast.next.next;
slow=slow.next;
}
return false
};
2021.11.05
//输入栈
let stack1 = []
//输出栈
let stack2 = []
function push(node)
{
// write code here
return stack1.push(node);
}
function pop()
{
// write code here
if(stack2.length === 0){
while(stack1.length !== 0)
{
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
var search = function(nums, target) {
let left = 0;
let right = nums.length-1;
while (left<=right){
var mid = left + Math.floor((right-left)/2);
if(nums[mid]>target){
right=mid-1
}else if (nums[mid]<target) {
left=mid+1
}else{
return mid;
}
}
return -1
};
2021.11.18
function levelOrder( root ) {
if(!root) return []
let res = [], queue = [root]
while (queue.length !== 0) {
const levelSize = queue.length
const currLevel = []
for (let i=0; i<levelSize; i++)
const node = queue.shift()
currLevel.push(node.val)
if (node.left) {
queue.push(node.left)
}
if (node.right) {
queue.push(node.right)
}
}
res.push(currLevel)
}
return res
};
替换功能,第一个参数(起始位置),第二个参数(删除的项数),第三个参数(插入任意数量的项)。
用法:array.splice(index,num,insertValue),返回值为删除内容,array为结果值。
思路:两个数字比较大小,如果nums1[i] > nums2[i] 就在nums1[i]前用splice(i, 0, nums2[i])
把nums2[i]插入
当循环到num1存0的位置直接把nums2剩下的插入就行了
var merge = function(nums1, m, nums2, n) {
let j = 0;
for (let i = 0; i < m + n; i++) {
if (nums1[i] > nums2[j]) {
nums1.splice(i, 0, nums2[j]);
j++;
nums1.pop();
}
if (i - j >= m) {
nums1.splice(i, 0, nums2[j]);
j++;
nums1.pop();
}
}
};
2021.11.10
时间复杂度为:O( n^2 );空间复杂度O(1)
function bubbleSort(nums) {
//每轮循环都从最后一个元素开始 比较并交换 一次循环会把最小的数顶到最上面
for (let i = 0; i < nums.length - 1; i++) { //只是控制次数为n-1
for (let j = nums.length - 1; j > i; j--) {
if (nums[j] < nums[j - 1]) {
//交换
let temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
}
}
}
}
//快速排序最差O(n^2)最优O(nlogn)
function swap(nums, i, j) {
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
function qsort(nums, l, r) {
if (r <= l) return; //注意定义递归中止条件
let pivot = nums[l]; //选择最左为轴值
swap(nums, l, r); //把轴值与最右交换
let i = l;
for (let j = l; j < r; j++) {
if (nums[j] < pivot) {
swap(nums, i, j);
i++;
}
}
swap(nums, i, r); //此时i为轴值下标
qsort(nums, l, i - 1);
qsort(nums, i + 1, r);
}
//堆排序 建堆O(n) 删除n个O(nlogn)
function heapSort(nums) {
if (nums.length <= 1) return nums;
let res = [];
let heapSize = nums.length;
buildHeap(nums, heapSize);
for (let i = 0; i < nums.length; i++) {
res.push(nums[0]);
swap(nums, 0, --heapSize);
siftDown(nums, 0, heapSize);
}
return res;
}
//建堆 (最小堆)
function buildHeap(nums, heapSize) {
for (let i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
siftDown(nums, i, heapSize);
}
}
//siftDown 调整堆
function siftDown(nums, i, heapSize) {
let smallest = i;
let l = 2 * i + 1;
let r = 2 * i + 2;
if (l < heapSize && nums[l] < nums[smallest]) {
smallest = l;
}
if (r < heapSize && nums[r] < nums[smallest]) {
smallest = r;
}
if (smallest != i) {
swap(nums, i, smallest);
siftDown(nums, smallest, heapSize);
}
}
//交换
function swap(nums, i, j) {
let temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
//test
nums = [5, 1, 4, 2, 8, 11, 2, 3];
let res = heapSort(nums);
console.log(res);
var mySqrt = function(x) {
if (x < 2) return x
let left = 1
let right = Math.floor(x / 2);
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2)
if (mid * mid === x) return mid
if (mid * mid < x) {
left = mid + 1
}else {
right = mid - 1
}
}
return right
};
2020.12.07
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
var removeElement = function(nums, val) {
var k =0;
for(i=0;i<nums.length;i++){
if(nums[i]!=val){
nums[k++]=nums[i]
}
}
return k;
};
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
var sortedSquares = function(nums) {
var result = [];
for(i=0,j=nums.length-1;i<=j;){
var right = Math.abs(nums[i]);
var left = Math.abs(nums[j]);
if(right>left){
result.unshift(right*right);
i++;
}else{
result.unshift(left*left);
j--;
}
}
return result;
};
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 。
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
var minSubArrayLen = function(target, nums) {
var left=right=sum=0;
var len=nums.length;
var res = len+1;
while(right<len){
sum+=nums[right++];
while(sum>=target){
res=res<right-left?res:right-left;
sum-=nums[left++];
}
}
//最后判断别忘
return res>len?0:res;
};
2021.12.08
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
var removeElements = function(head, val) {
var ret = new ListNode(0,head);
var cur = ret;
while(cur.next){
if(cur.next.val===val){
cur.next=cur.next.next;
continue;
}
cur = cur.next
}
return ret.next
};
var reverseList = function(head) {
var prev = null;
var curr = head;
while(curr){
next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;
};
2021.12.09
双指针
var removeNthFromEnd = function(head, n) {
let ret = new ListNode(0, head),
slow = fast = ret;
while(n--) fast = fast.next;
while (fast.next) {
fast = fast.next;
slow = slow.next
};
slow.next = slow.next.next;
return ret.next;
};
2021.12.10
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
var getListLen = function(head) {
let len = 0, cur = head;
while(cur) {
len++;
cur = cur.next;
}
return len;
}
var getIntersectionNode = function(headA, headB) {
let curA = headA,curB = headB,
lenA = getListLen(headA),
lenB = getListLen(headB);
if(lenA < lenB) {
[curA, curB] = [curB, curA];
[lenA, lenB] = [lenB, lenA];
}
let i = lenA - lenB;
while(i-- > 0) {
curA = curA.next
}
while(curA && curA !== curB) {
curA = curA.next;
curB = curB.next;
}
return curA;
};
var hasCycle = function(head) {
if(head === null || head.next === null) {
return false;
}
var slow=head;
var fast=head.next;
while(fast&&fast.next){
if(fast==slow){
return true
}
fast=fast.next.next;
slow=slow.next;
}
return false
};
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
var isAnagram = function(s, t) {
var map = {};
for(v of s){
if(map[v]){
map[v]=map[v]+1
}else{
map[v]=1
}
}
for(i of t){
if(map[i]){
map[i]=map[i]-1
}else{
map[i]=1
}
}
return Object.values(map).every(v=>v==0);
};
2021.12.11
var intersection = function(nums1, nums2) {
let hash1=new Set(nums1);
let hash2=new Set();
for(var i=0;i<nums2.length;i++){
if(hash1.has(nums2[i])){
hash2.add(nums2[i])
}
}
return [...hash2]
};
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
var isHappy = function (n) {
let m = new Map()
const getSum = (num) => {
let sum = 0
while (n) {
sum += (n % 10) ** 2
n = Math.floor(n / 10)
}
return sum
}
while (true) {
// n出现过,证明已陷入无限循环
if (m.has(n)) return false
if (n === 1) return true
m.set(n, 1)
n = getSum(n)
}
}
2021.12.13
// obj[target-nums[i]]=obj.[target-nums[i]]
var twoSum = function(nums, target) {
let obj = {};
for(let i = 0;i<nums.length;i++){
if(obj[target-nums[i]]!==undefined){
return[i,obj[target-nums[i]]]
}
obj[nums[i]]=i;
}
};
2021.12.13
var canConstruct = function(ransomNote, magazine) {
let table = new Array(26).fill(0);
base = "a".charCodeAt();
for(let s of magazine){
table[s.charCodeAt()-base]++;
}
for(let s of ransomNote){
const index = s.charCodeAt()-base;
if(!table[index]) return false;
table[index]--;
}
return true;
};
var reverseString = function(s) {
var l =-1; var r = s.length;
while(++l<--r){
[s[l],s[r]]=[s[r],s[l]]
}
return s
};
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
var reverseStr = function(s, k) {
const len = s.length;
let resArr = s.split("");
for(let i = 0; i < len; i += 2 * k) {
let l = i - 1, r = i + k > len ? len : i + k;
while(++l < --r) [resArr[l], resArr[r]] = [resArr[r], resArr[l]];
}
return resArr.join("");
};
2021.12.14
把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
var replaceSpace = function(s) {
// 字符串转为数组
const strArr = Array.from(s);
let count = 0;
// 计算空格数量
for(let i = 0; i < strArr.length; i++) {
if (strArr[i] === ' ') {
count++;
}
}
let left = strArr.length - 1;
let right = strArr.length + count * 2 - 1;
while(left >= 0) {
if (strArr[left] === ' ') {
strArr[right--] = '0';
strArr[right--] = '2';
strArr[right--] = '%';
left--;
} else {
strArr[right--] = strArr[left--];
}
}
// 数组转字符串
return strArr.join('');
};
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
var reverseLeftWords = function(s, n) {
var length = s.length;
let i = 0;
while (i < length - n){
s = s[length - 1] + s;
i++;
}
return s.slice(0,length);
};
2021.12.15
输入:haystack = “hello”, needle = “ll”
输出:2
var strStr = function (haystack, needle) {
if (needle.length === 0)
return 0;
const getNext = (needle) => {
let next = [];
let j = 0;
next.push(j);
for (let i = 1; i < needle.length; ++i) {
while (j > 0 && needle[i] !== needle[j])
j = next[j - 1];
if (needle[i] === needle[j])
j++;
next.push(j);
}
return next;
}
let next = getNext(needle);
let j = 0;
for (let i = 0; i < haystack.length; ++i) {
while (j > 0 && haystack[i] !== needle[j])
j = next[j - 1];
if (haystack[i] === needle[j])
j++;
if (j === needle.length)
return (i - needle.length + 1);
}
return -1;
};
2021.12.17
kmp,如果len % (len - (next[len - 1] + 1)) == 0 ,则说明 (数组长度-最长相等前后缀的长度) 正好可以被 数组的长度整除,说明有该字符串有重复的子字符串。
数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。
var repeatedSubstringPattern = function (s) {
if (s.length === 0)
return false;
const getNext = (s) => {
let next = [];
let j = 0;
next.push(j);
for (let i = 1; i < s.length; ++i) {
while (j > 0 && s[i] !== s[j])
j = next[j - 1];
if (s[i] === s[j])
j++;
next.push(j);
}
return next;
}
let next = getNext(s);
if (next[next.length - 1] !== 0 && s.length % (s.length - next[next.length - 1]) === 0)
return true;
return false;
};
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
var fib = function(n) {
var dp = [];
if(n==0){
return 0
}
if(n == 1){
return 1
}
dp[0] =0;
dp[1]=1;
for(var i =2;i<=n;i++){
dp[i]=(dp[i-1]+dp[i-2])% 1000000007
}
return dp[n];
};
2021.11.11
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
<script>
function pay() {
console.log("点击")
}
function debounce (func,delay) {
let timer;
// 闭包
return function () {
let contest = this;
clearTimeout(timer);
timer = setTimeout(() => {
// 需要防抖的操作...
func().apply(contest, arguments);
console.log("防抖成功!");
}, delay);
}
}
var btn1 = document.getElementById('debounce');
btn1.addEventListener("click", debounce(pay,5000));
</script>
函数被触发时,只响应在某个固定时间短内的第一次请求,后续的请求都不响应,直到下个时间周期,继续响应下个周期内的第一次请求,周而复始。
<button id="debounce">节流</button>
<script>
function pay() {
console.log("节流")
}
function debounce (func,delay) {
let flag = true;
return function () {
if (!flag) return false;
flag = false;
setTimeout(() => {
func.apply(this, arguments);
flag = true;
}, delay)
}}
var btn1 = document.getElementById('debounce');
btn1.addEventListener("click", debounce(pay,1000));
</script>
2021.11.14
reduce相当于一个累加器
function sum(...args) {
//对第一层参数求和
let x = args.reduce((acc, next) => {
return acc + next;
})
// 返回一个新的函数
return function (...args2) { //第二层的参数
// 当没有第二层参数时,返回x即可
if (args2.length == 0) return x;
let y = args2.reduce((acc, next) => {
return acc + next;
})
return sum(x + y); //返回x+y作为新的第一层
}
}
console.log(sum(1, 2)(3)(4)()); // 10
String.prototype.trim = function () {
// \s 为任意的空白符. 包括空格,换行符,制表 符,换页符
return this.replace(/^\s+/g, "").replace(/\s+$/g, "");
}
//concat() 方法用于连接两个或多个数组。此方法返回一个新数组,不改变原来的数组。
function flatten(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
let arr = [1, 2, 3, [4, 5, 6, [7, 8, 9]], 10];
console.log(flatten(arr));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
img {
display: block;
width: 100%;
height: 300px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
<img data-src="mao.jpg" alt="">
</body>
<script>
var imgs = document.querySelectorAll('img');
//获得元素距离页面顶部的距离,(到浏览器顶部的距离)
function getTop(e){
return e.offsetTop;
}
function lazyLoad(imgs) {
//获取可视区高度
var H = window.innerHeight || document.documentElement.clientHeight;
//滚动区域高度
var S = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
for (let i = 0; i < imgs.length; i++) {
//图片距离顶部的距离大于可视区域和滚动区域之和时懒加载
if (H + S > getTop(imgs[i])) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onload = window.onscroll = function () {
lazyLoad(imgs);
}
</script>
</html>
//浅拷贝
function shallowCopy(obj) {
var copy = {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key]
}
}
return copy;
}
//深拷贝
function deepClone(obj){
var clone;
if (obj && typeof obj !== 'object') clone = obj;
else {
clone = Array.isArray(obj) ? [] : {};
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
if (obj[k] && typeof obj[k] === 'object') {
clone[k] = deepClone(obj[k]);
} else {
clone[k] = obj[k];
}
}
}
}
return clone;
}
//test
let obj = {
name: 'vivian',
age: 18,
mark: {
one: 1,
two: 2
},
arr: [1, 2, 3]
}
let shallow=shallowCopy(obj)
let deep = deepClone(obj);
obj.arr[0]=10;
console.log(shallow);
console.log(deep);
//call,改变this指向 调用函数
Function.prototype.mycall = function (context, ...arg) {
context.fn = this; //this是test函数,把他作为context的方法而存在
let res = context.fn(...arg);
delete context.fn;
return res;
}
//test
let obj = {
name: 'vivian'
}
function test(arg1, arg2, arg3) {
console.log(this.name);
console.log(arg1, arg2, arg3);
}
test.mycall(obj, 1, 2, 3);
//apply,改变this指向 调用函数参数为数组
Function.prototype.myApply = function (context, arg) {
context.fn = this;
let res;
if (!arg) {
res = context.fn();
} else {
res = context.fn(...arg);
}
delete context.fn;
return res;
}
//bind改变this指向,不调用函数
Function.prototype.mybind = function (context, ...arg) {
let fun = this;
return function () {
return fun.apply(context, arg)
}
}
(1)利用浮动,将左边元素宽度设置为200px,并且设置向左浮动。将右边元素的margin-left设置为200px,宽度设置为auto(默认为auto,撑满整个父元素)。
<style>
.outer{
height: 500px;
}
.left{
float: left;
width: 200px;
height: 500px;
background-color: tomato;
}
.right{
margin-left: 200px;
height: 500px;
width: auto;
background-color: greenyellow;
}
</style>
<div class="outer">
<div class="left">left</div>
<div class="right">right</div>
</div>
利用浮动,左侧元素设置固定大小,并左浮动,右侧元素设置overflow: hidden; 这样右边就触发了BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。
.left{
width: 100px;
height: 300px;
background: red;
float: left;
}
.right{
height: 300px;
background: blue;
overflow: hidden;
}
(2)利用flex布局,将左边元素设置为固定宽度200px,将右边的元素设置为flex:1。
.outer {
display: flex;
height: 100px;
}
.left {
width: 200px;
background: tomato;
}
.right {
flex: 1;
background: gold;
}
(3)利用绝对定位,将父级元素设置为相对定位。左边元素设置为absolute定位,并且宽度设置为200px。将右边元素的margin-left的值设置为200px。
.outer {
position: relative;
height: 100px;
}
.left {
position: absolute;
width: 200px;
height: 100px;
background: tomato;
}
.right {
margin-left: 200px;
background: gold;
}
利用绝对定位,将父级元素设置为相对定位。左边元素宽度设置为200px,右边元素设置为绝对定位,左边定位为200px,其余方向定位为0。
.outer {
position: relative;
height: 100px;
}
.left {
width: 200px;
background: tomato;
}
.right {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 200px;
background: gold;
}