最近公司內部在開始作前端技術的技術分享,每週一個主題的 每週一練,以基礎知識爲主,感受挺棒的,跟着團隊的大佬們學習和複習一些知識,新人也能夠多學習一些知識,也把團隊內部學習氛圍營造起來。前端
我接下來會開始把每週一練的題目和知識整理一下,便於思考和鞏固,就像今天這篇開始。git
學習的道路,很漫長,要堅持,但願你們都能掌握本身喜歡的技術,和本身須要的技術。es6
本週練習內容:數據結構與算法 —— Stack算法
這些都是數據結構與算法,一部分方法是團隊其餘成員實現的,一部分我本身作的,有什麼其餘實現方法或錯誤,歡迎各位大佬指點,感謝。數組
push(element)
:添加一個新元素到棧頂。pop()
:移除棧頂的元素,同時返回被移除的元素。peek()
:返回棧頂的元素,不對棧作任何修改 (這個方法不會移除棧頂的元素,僅僅返回它)。isEmpty()
:若是棧沒有任何元素就返回 true
,不然返回 false
。clear()
:移除棧裏面的全部元素。size()
:返回棧裏的元素個數。這個方法與數組的 length
屬性相似。方法1:ES6實現微信
class Stack {
constructor (){
this.items = []
}
push( element ){
this.items.push(element)
}
pop(){
return this.items.pop()
}
peek(){
return this.items[this.items.length - 1]
}
isEmpty(){
return this.items.length === 0
}
clear(){
this.items = []
}
size(){
return this.items.length
}
}
複製代碼
上面實現的方式雖然簡單,可是內部 items
屬性是公共的,爲了知足面向對象變成私有性的原則,咱們應該讓 items
做爲私有屬性,所以咱們可使用 ES6 中 Symbol
或 WeakMap
來實現:數據結構
方法2:使用 ES6 的 Symbol 基本數據類型實現
知識點複習:ES6 中的 Symbol 介紹函數
const _items = Symbol()
class Stack {
constructor (){
this[_items] = []
}
push (element){
this[_items].push(element)
}
// 剩下方法和第一種實現的差很少,這裏省略
// 只要把前面方法中的 this.items 更改成 this[_items]
}
複製代碼
方法3:使用 ES6 的 WeakMap 實現
知識點複習:ES6 中的 WeakMap 介紹學習
const items = new WeakMap()
class Stack {
constructor (){
items.set(this, [])
}
push (element){
let item = items.get(this)
item.push(element)
}
// 剩下方法和第一種實現的差很少,這裏省略
// 只要把前面方法中的獲取 this.items 的方式,更改成 items.get(this) 獲取
}
複製代碼
題目意思很簡單,就是十進制轉二進制,可是在實際工做開發中,咱們更願意實現的是任意進制轉任意進制,不過呢,咱們仍是以解決問題爲首要目標呀。
固然,業務需求能夠直接使用 toString(2)
方法,可是爲了練習,咱仍是不這麼用咯。
方法1:使用前面定義的 Stack 類
這裏使用前面題目中定義的 Stack
類。
/** * 十進制轉換爲二進制 * @param {Number} bit */
function bitset (bit){
if(bit == 0) return '0'
if(!/^[0-9]+.?[0-9]*$/.test(bit)){
return new Error('請輸入正確的數值!')
}
let stack = new Stack(), result = ''
while (bit > 0){
stack.push(bit % 2)
bit = Math.floor(bit / 2)
}
while (!stack.isEmpty()){
result += stack.pop().toString()
}
return result
}
複製代碼
方法2:簡單實現
下面這個方法,其實不太好,由於沒有怎麼用到此次要練習的棧方法,哈哈。
/** * 十進制轉換爲二進制 * @param {Number} bit */
function bitset (bit){
if(bit == 0) return '0'
if(!/^[0-9]+.?[0-9]*$/.test(bit)){
return new Error('請輸入正確的數值!')
}
let arr = []
while(bit > 0){
arr.push(bit % 2)
bit = Math.floor(bit / 2)
}
return arr.reverse().join('')
}
複製代碼
另外能夠參考:wikiHow - 從十進制轉換爲二進制。
主要目的就是:該函數接收一個圓括號字符串,判斷裏面的括號順序是否有效,若是有效則返回 true
反之 false
。
如:
(
-> false
()
-> true
(()
-> false
())
-> false
())
-> false
(((()()))())
-> true
這個題目實現的主要方法是:遍歷字符串,先排除錯誤狀況,而後將 (
入棧保存,將 )
入棧匹配前一個元素是不是 (
,若是是,則 pop()
前一個元素 (
,若是不是,則 push()
這個 )
入棧,最終查看棧是否爲空,如果則檢驗成功,不然失敗。
方法1:使用前面定義的 Stack 類
這裏使用前面題目中定義的 Stack
類。
/** * 檢驗圓括號順序的有效性 * @param {String} str */
function validParentheses (str){
if(!str || str.length === 0 || str[0] === ')') return false
let stack = new Stack()
str.split('').forEach(char => {
let status = stack.peek() === '(' && char === ')'
status ? stack.pop() : stack.push(char)
})
return stack.isEmpty()
}
複製代碼
方法2:出入棧操做
/** * 檢驗圓括號順序的有效性 * @param {String} str */
function validParentheses (str){
if(!str || str.length === 0 || str[0] === ')') return false
let arr = []
for(let i = 0; i < str.length ; i++){
str[i] === '(' ? arr.push(str[i]) : arr.pop()
}
return arr.length === 0
}
複製代碼
步驟 | 數據棧 | 輔助棧 | 最小值 |
---|---|---|---|
1.push 3 | 3 | 0 | 3 |
2.push 4 | 3, 4 | 0, 0 | 3 |
3.push 2 | 3, 4, 2 | 0, 0, 2 | 2 |
4.push 1 | 3, 4, 2 ,1 | 0, 0, 2, 3 | 1 |
5.pop | 3, 4, 2 | 0, 0, 2 | 2 |
6.pop | 3, 4 | 0, 0 | 3 |
7.push | 3, 4 ,0 | 0, 0, 2 | 0 |
使用示例以下:
let stack = new Stack();
stack.push(3);
console.log('After push 3, Min item is', stack.min());
stack.push(4);
console.log('After push 4, Min item is', stack.min());
stack.push(2);
console.log('After push 2, Min item is', stack.min());
stack.push(1);
console.log('After push 1, Min item is', stack.min());
stack.pop();
console.log('After pop, Min item is', stack.min());
stack.pop();
console.log('After pop, Min item is', stack.min());
stack.push(0);
console.log('After push 0, Min item is', stack.min());
複製代碼
提示:利用輔助棧(Web 端可利用數組),每次對棧 push/pop 元素時,也同時更新輔助棧(存儲最小元素的位置)
方法1:小操做
class Stack {
constructor() {
this.items = [];
this.minIndexStack = [];
}
push(element) {
this.items.push(element);
let minLen = this.minIndexStack.length;
let minItemIndex = this.minIndexStack[minLen - 1];
if(minLen === 0 || this.items[minItemIndex] > item) {
this.minIndexStack.push(this.items.length - 1);
} else {
this.minIndexStack.push(minItemIndex);
}
}
pop() {
this.minIndexStack.pop();
return this.items.pop();
}
min() {
let len = this.minIndexStack.length;
return (len > 0 && this.items[this.minIndexStack[len - 1]]) || 0;
}
peek() {
return this.items[this.items.length - 1];
}
// 省略其它方法
}
複製代碼
方法2:與方法1中push實現的差別
class Stack {
constructor (){
this.items = [] // 數據棧
this.arr = [] // 輔助棧
}
push( element ){
this.items.push(element)
let min = Math.min(...this.items)
this.arr.push( min === element ? this.size() - 1 : 0)
}
pop(){
this.arr.pop()
return this.items.pop()
}
peek(){
return this.items[this.items.length - 1]
}
isEmpty(){
return this.items.length === 1
}
clear(){
this.items = []
}
size(){
return this.items.length
}
min (){
let last = this.arr[this.arr.length - 1]
return this.items[last]
}
}
複製代碼
下週將練習隊列(Queue) 的題目,開始翻起算法書籍學習咯。