- 力扣 (LeetCode)-两数之和,有效的括号,两数相加|刷题打卡-3月1日
- 力扣 (LeetCode)-合并两个有序链表,删除排序数组中的重复项,JavaScript笔记|刷题打卡-3月2日
- 力扣 (LeetCode)-最大子序和,JavaScript数据结构与算法(数组)|刷题打卡-3月3日
- 针对CSS说一说|技术点评-3月4日
前言
如果这篇文章有帮助到你,给个❤️关注,❤️点赞,❤️鼓励一下作者,接收好挑战了吗?文章公众号首发,关注 程序员哆啦A梦 第一时间获取最新的文章
❤️笔芯❤️~
栈
栈是一种 后进先出 的有序集合。新添加或待删除的元素都保存在栈的同一端,叫做栈顶,另外一端叫栈底。
创建栈
创建一个类来表示栈:(如何使用Stack类)
代码语言:javascript复制function Stack() {
// 各种属性和方法的声明
}
声明数组,保存栈里的元素:
代码语言:javascript复制let items = []
push()
,添加一个或几个新元素到栈顶pop()
,移除栈顶的元素,同时返回被移除的元素peek()
,返回栈顶的元素,不对栈做任何修改isEmpty()
,如果栈里没有任何元素就返回true,否则返回falseclear()
,移除栈里的所有元素size()
,返回栈里的元素个数
向栈添加元素(往栈里添加新元素)
示例:
代码语言:javascript复制// 只添加元素到栈顶,也就是栈的末尾
this.push = function(element) {
items.push(element);
});
从栈移除元素(移出的是最后添加进去的元素)
示例:
代码语言:javascript复制this.pop = function() {
return items.pop();
};
查看栈顶元素(用于想找到栈里面最后添加的元素是什么)
示例,返回栈顶的元素:
代码语言:javascript复制this.peek = function() {
return items[items.length-1];
};
检查栈是否为空
如果栈为空的话将返回true,否则就返回false。
示例:
代码语言:javascript复制this.isEmpty = function() {
return items.length == 0;
};
返回栈的长度:
代码语言:javascript复制this.size = function() {
return items.length;
};
清空和打印栈元素
clear
方法用来移除栈里所有的元素,把栈清空。
this.clear = function() {
items = [];
};
把栈里的元素都输出来:
代码语言:javascript复制this.print = function() {
console.log(item.toString());
};
使用Stack类
初始化Stack类:
代码语言:javascript复制let stack = new Stack();
console.log(stack.isEmpty()); //输出为true
往栈里添加一些元素
代码语言:javascript复制stack.push(1);
stack.push(2);
如果调用peek方法,将会输出2
代码语言:javascript复制console.log(stack.peek()); //输出2
如何用ES6声明Stack类
代码:
代码语言:javascript复制// 在类的构造函数constructor里声明, ES6的类是基于原型的。
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
}
基于原型的类比基于函数的类更节省内存,也更适合创建多个实例,却不能够声明私有属性或方法。
- 用
ES6
的限定作用域Symbol
实现类
ES6
新增了一种叫做Symbol
的基本类型,它是不可变的,可以用作对象的属性。
示例:
代码语言:javascript复制// 声明了Symbol类型的变量_items,在类的constructor函数中初始化它的值
let _items = Symbol();
class Stack {
constructor() {
this[_items] = [];
}
}
使用ES6
新增的Object.getOwnPropertySymbols
方法能够取到类里面声明的所有Symbols
属性。
let stack = new Stack();
stack.push(2);
stack.push(3);
let objectSymbols = Object.getOwnPropertySymbols(stack);
console.log(objectSymbols.length); // 1
console.log(objectSymbols); // [Symbol()] 数组Symbols属性
console.log(objectSymbols[0]); // Symbol()
stack[objectSymbols[0]].push(1);
stack.print(); //输出 2, 3, 1
访问
stack[objectSymbols[0]]
获得_items
的,_items
属性是一个数组,可以进行任意的数组操作。所以不该使用这种方法。
ES6
中的WeakMap
实现类
使用WeakMap
确保属性是私有的,WeakMap
可以存储键值对,其中键是对象,值可以是任意数据类型。
示例:
代码语言:javascript复制// 声明了一个WeakMap类型的变量items
const items = new WeakMap(); // 谁都可以改动它
class Stack {
constructor () {
// 在constructor中,以this为键,把代表栈的数组存入items
items.set(this, []);
}
push(element) {
// 从WeakMap中取出值,即以this为键从items中取值
let s = items.get(this);
s.push(element);
}
pop() {
let s = items.get(this);
let r = s.pop();
return r;
}
//其他方法
}
itmes
在Stack
类里是真正的所有属性了。
使用闭包:
代码语言:javascript复制// 当Stack函数里的构造函数被调用时,会返回Stack类的一个实例
let Stack = (function () {
const items = new WeakMap();
class Stack {
constructor () {
items.set(this, []);
}
//其他方法
}
return Stack; //当被调用时,会返回Stack类的一个实例
})();
// 使用这种方法,扩展类无法继承私有属性
十进制转二进制问题算法
示例:
代码语言:javascript复制function divideBy2(decNumber){
var remStack = new Stack(),
rem,
binaryString = '';
while (decNumber > 0){
rem = Math.floor(decNumber % 2);
remStack.push(rem);
decNumber = Math.floor(decNumber / 2);
}
while (!remStack.isEmpty()){
binaryString = remStack.pop().toString();
}
return binaryString;
}
十进制转换成任何进制
示例:
代码语言:javascript复制function baseConverter(decNumber, base){
var remStack = new Stack(),
rem,
baseString = '',
// 多了digits
digits = '0123456789ABCDEF';
// 基数
while (decNumber > 0){
rem = Math.floor(decNumber % base);
remStack.push(rem);
decNumber = Math.floor(decNumber / base);
}
while (!remStack.isEmpty()){
baseString = digits[remStack.pop()];
}
return baseString;
}
两数之和
解题思路:
- 暴力法
- 哈希表法
示例伪代码:
代码语言:javascript复制func(nums,target) -> []
result = []; [0,1] 长度为2
for i in [0, len(nums)]; // 不动
for j in [i 1, len(nums)]; // 移动
sum = nums[i] nums[j];
if sm == target;
result[0] = i
result[1] = j
result result
伪代码:
代码语言:javascript复制func(nums, target) -> [];
result = []
map = HashTable()
for i in [0, len(nums)];
map.add(nums[i], i);
for j in [0, len(nums)];
diff = target - nums[j]
if(map.containskey(diff) and map.get(diff) != j)
result[0] = j
result[1] = map.get(diff)
return result
两数相加
- 迭代法
- 递归法
伪代码:
代码语言:javascript复制func (l1, l2) -> Listnode
total = 0 // 两个相加的和是多少
next1 = 0 // 下一个进位
result = ListNode()
cur = result
while (l1 != null and l2 != null);
total = l1.val l2.vale next1
cur.next = ListNode(total)
next1 = total / 10
l1 = l1.next
l2 = l2.next
cur = cur.next
while l1 != null
total = l1.val next1
cur.next = ListNode(total)
nextl = total / 10
l1 = l1.next
cur = cur.next
while l2 != null
total = l2.val next1
cur.next = ListNode(total)
next1 = total / 10
l2 = l2.next
cur = cur.next
if next1 ! = 0
cur.next = ListNode(next1)
return reult.next
递归法:
伪代码:
代码语言:javascript复制func (l1, l2) -> ListNode
total = l1.val l2.val
next1 = total / 10
res = ListNode(total % 10)
if( l1.next != null or l2.next != null or next1 != 0 )
if(l1.next ! = null)
l1 = l1.next
else
l2 = ListNode(0)
if(l2.next != null)
l2 = l2.next
else
l2 = ListNode(0)
l1.val = l1.val next1
res.next = fun(l1,l2)
return res
有效的括号
栈的解法:
代码语言:javascript复制var isValid = function (s) {
let valid = true;
const stack = [];
const mapper = {
"{": "}",
"[": "]",
"(": ")",
};
for (let i in s) {
const v = s[i];
if (["(", "[", "{"].indexOf(v) > -1) {
stack.push(v);
} else {
const peak = stack.pop();
if (v !== mapper[peak]) {
return false;
}
}
}
if (stack.length > 0) return false;
return valid;
};
合并两个有序链表
- 迭代法
- 递归法
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
const mergeTwoLists = function (l1, l2) {
if (l1 === null) {
return l2;
}
if (l2 === null) {
return l1;
}
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
};
22. 括号生成
一、题目描述
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
代码语言:javascript复制示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
提示:
1 <= n <= 8
二、思路分析
- 回溯法
伪代码:
代码语言:javascript复制fun(n) -> []
result = []
backtracking(n,result,0,0, "")
return result
backtracking(n,result,left,right,str) -> void
if right > left
return
if left == right == n
result.add(str)
return
if left<n
backtracking(n,result,left 1,right,str "(")
if right<left
backtracking(n,result,left,right 1,str ")")
三、答案代码
示例:
代码语言:javascript复制/**
* @param {number} n
* @return {string[]}
* @param l 左括号已经用了几个
* @param r 右括号已经用了几个
* @param str 当前递归得到的拼接字符串结果
* @param res 结果集
*/
const generateParenthesis = function (n) {
const res = [];
function dfs(l, r, str) {
if (l == n && r == n) {
return res.push(str);
}
// l 小于 r 时不满足条件 剪枝
if (l < r) {
return;
}
// l 小于 n 时可以插入左括号,最多可以插入 n 个
if (l < n) {
dfs(l 1, r, str "(");
}
// r < l 时 可以插入右括号
if (r < l) {
dfs(l, r 1, str ")");
}
}
dfs(0, 0, "");
return res;
};
四、总结
栈,括号生成分析
回看笔者往期高赞文章,也许能收获更多喔!
- 一个合格的初级前端工程师需要掌握的模块笔记
- Vue.js笔试题解决业务中常见问题
- 【初级】个人分享Vue前端开发教程笔记
- 长篇总结之JavaScript,巩固前端基础
- 前端面试必备ES6全方位总结
- 达达前端个人web分享92道JavaScript面试题附加回答
- 【图文并茂,点赞收藏哦!】重学巩固你的Vuejs知识体系
- 【思维导图】前端开发-巩固你的JavaScript知识体系
- 14期-连肝7个晚上,总结了计算机网络的知识点!(共66条)