一道二進位制子串演算法讓面試官都解不出來?
演算法題目:
給定一個字串 s ,計算具有相同數量0和1的非空(連續)子字串的數量,並且這些子字串中的所有0和所有1都是組合在一起的。
重複出現的 子串要計算它們出現的次數。
示例1:
輸入:"00110011" 輸出:6 解釋:有6個子串具有相同數量的連續1和0:
“0011”,“01”,“1100”,“10”,“0011”,“01”。
注意,一些重複出現的子串要計算它們出現的次數,另外, “00110011”不是有效的子串,因為所有的0(和1)沒有組合在一起。
示例2:
輸入:“10101” 輸出:4 解釋:有4個子串,“10”,“01”,“10”,“01”,它們具有相同數量的連續1和0。
注意:s.length 在1到50,000之間的範圍,s只包含“0”或“1”字元。
“000111”中有多少個有效的二進位制子串,“11100”中有多少個有效的二進位制子串?“00011100”呢?
這道題目,難度係數為簡單題目,涉及到的知識點為字串。
JavaScript的解法:
給定函式體:
/** * @param {string} s * @return {number} */ var countBinarySubstrings = function(s) {
};
題目理解:
通過看看這兩個示例,字串 s 給的都是二進位制數,要求計算具有相同數量 0 和 1 的非空(連續)子字串的數量,這句話裡面的條件有三個:
第一 不為空,非空(連續)
第二 0 和 1 是要相同數量的
第三 0 和 1 要是連續出現的子字串的數量
描述:
如果遇到10或者是01的情況,則說明連續的1或者是連續的0斷了,那麼可以拿到前面連續1或者是連續0的數量,然後再查詢後面連續1或者是連續0的數量,作比較看看有多少個符合的子串。
目錄:
第一種JavaScript:
``` var countBinarySubstrings = function(s) { // 前面一個數,和當前數 let pre=0, count=0, count1=0, count2=0; // 迴圈字串 for(let i = 1; i < s.length; i++) { // 遇到10或01的情況,則說明連續的1或連續的0斷了 if(s[i] !== s[pre]) { if(count1 === 0) { // 拿到前面連續1或0的數量 count1 = i - pre; pre = i; } else { count2 = i - pre; count += count1 > count2 ? count2 : count1; count1 = count2; count2 = 0; pre = i; } } if(i === s.length - 1) { count2 = s.length - pre; count += count1 > count2 ? count2 : count1; } }
return count; } ```
第二種JavaScript:
/**
* @param {string} s
* @return {number}
*/
var countBinarySubstrings = function(s) {
// 字串的長度
const len = s.length;
// 次數為0,前一個為0,current當前為1。
let n = 0, pre = 0, current = 1;
// 迴圈字串
for(let i = 0; i<len; i++){
if(s[i] === s[i+1]) {
current++;
}else {
// 比如00011,就有2組
if(pre > 0) {
n += Math.min(pre.current);
}
pre = current;
current = 1;
}
}
return n;
};
JavaScript min() 方法
返回值:給定數值中最小的數。如果任一引數不能轉換為數值,則返回NaN。
描述
由於 min 是 Math 的靜態方法,所以應該像這樣使用:Math.min(),而不是作為你建立的 Math 例項的方法(Math 不是建構函式)。
如果沒有引數,結果為Infinity。如果有任一引數不能被轉換為數值,結果為 NaN。
JavaScript Math 物件
定義和用法
min() 方法可返回指定的數字中帶有最低值的數字。
Math.min.apply(null, arr)
var array=[2,6,5,8,7];
Math.min.apply(null,array);
第三種JavaScript:
/**
* @param {string} s
* @return {number}
*/
var countBinarySubstrings = function(s) {
// res 儲存相鄰連續字串的個數
let res = [];
let temp = s[0];
let count = 0;
for(let i of s) {
// 迴圈字串
if(i !== temp) {
res.push(count);
temp = i;
count = 0;
}
count++;
}
res.push(count);
let total = 0;
for(let i=0; i<res.length-1; i++){
total += Math.min(res[i], res[i+1]);
}
return total;
};
如何使用 min() 來返回指定數字中帶有最低值的數字:
```
document.write(Math.min(5,7) + "") document.write(Math.min(-3,5) + "
") document.write(Math.min(-3,-5) + "
") document.write(Math.min(7.25,7.30))
``` 輸出:
5
-3
-5
7.25
解題規律
- 000111必定有三個子串
- 00011必定有兩個子串
- 0111必定有1個子串
以此類推, 每兩組資料之間長度最短的值為子串的數量 把字串按數字分組切割,如:['00', '11', '00', '11'] 但是如果 是 1010100 這種,怎麼解釋才合理呢?
``` /** * @param {string} s * @return {number} */ var countBinarySubstrings = function(s) { let num = 0; const arr = s.match(/0+|1+/g); // let n = 0, arr = s.match(/([1]+)|([0]+)/g)
// 把字串切割成['00', '11', '00', '11']這樣的陣列
for(let i = 0, len = arr.length; i < len - 1; i++){
num += Math.min(arr[i].length, arr[i+1].length);
// 相鄰比較,長度更短的則為這一組的出現次數
}
return num; } ```
程式碼註解
``` /** * @param {string} s * @return {number} */ var countBinarySubstrings = function(s) { // 計算前一個字元連續出現的次數 let pre = 0 // 計算後一個字元連續出現的次數 let cur = 1 // 每當 pre >= cur 時,既滿足條件一次 count++ // 前面有兩個0,後面它自己為1 // 計數count一開始為0 let count = 0
// 迴圈字串
for(let i=1; i<s.length; i++) {
// 如果前一個和後一個相等
if(s[i] === s[i-1]) {
// 本身當前它自己的數為1,那麼兩者相等,這個數就+1,為2
cur++
// 00
} else {
// 當出現不一樣的字元時,現任變前任,現任重新計數
// 01,001,10,101,不一樣的前後,10,01
// 請一個數字的數量為1,後一個數字的數量為1
pre = cur
// 01,10, 當前數還是1
cur = 1
}
// 001, 110, 010, 101,
// 只要 pre >= cur, 即可滿足條件一次
if(pre >= cur) {
count++
}
}
return count
}; ```
看了程式碼解析應該是懂的了,不過在這裡還是口述一下下。
滿是條件為01或者是10,就是兩者不同,計數加1,出現001,或者是110的情況下,為前面2個0,後面1個1,前面的數量大於後面的數量即為滿足一次條件,110的情況也是如此,1的數量為2,0的數量為1。
那麼我們來定義一個變數let pre這個變數,這個變數的意思為計算前一個字串出現的次數,首先這個變數的初始化值為0。如果當前數為 1,那麼前面就沒有數字,即為它的數量為0。
這裡我們需要設定當前數量為1,即出現一個數字,那麼數量即為1個。滿足條件為前面的數量大於等於後面的數量,即為pre>=cur時,我們計數滿足條件加1的情況,定義計數為count,滿足條件時,count++
// 計算前一個字元連續出現的次數
let pre = 0
// 計算後一個字元連續出現的次數
let cur = 1
// 每當 pre >= cur 時,既滿足條件一次 count++
// 前面有兩個0,後面它自己為1
// 計數count一開始為0
let count = 0
注意:計算前一個字元連續出現的次數和計算後一個字元連續出現的次數不同哦!
然後我們給定一個字串數字,“00110011”,我們需要迴圈這個字串中的數字,比較前一個數字和後一個數字是否相等,如果相等,是什麼情況呢?如:00或者是11的情況下,當前數cur就要加1。
如果出現不一樣的字元時,即情況:10或者是01這些情況,那麼計算前一個字元連續出現的次數從0變為1,它有數字,即開始有次數了。把當前cur的次數賦值給pre(計算前一個字元連續出現的次數)。看著01和10的情況,當前cur的次數賦值為1。
滿足條件,有人問了,那麼001的情況或者是110或者是1100或者是0011或者是111000或者是000111或者是1010等情況下呢?
即這些情況滿足如下:計算前一個字元連續出現的次數大於等於計算後一個字元連續出現的次數,即為pre>=cur的條件下滿足,計數情況count++,迴圈字串後,返回我們需要的count計數。
總結:
好了,本章已結束,如果還有什麼不懂的,請在下方評論進行商議!
❤️ 不要忘記留下你學習的腳印 [點贊 + 收藏 + 評論]
大前端開發,定位前端開發技術棧部落格,PHP後臺知識點,web全棧技術領域,資料結構與演算法、網路原理等通俗易懂的呈現給小夥伴。謝謝支援,承蒙厚愛!!!
請點贊!因為你們的贊同/鼓勵是我寫作的最大動力!
相關文章
- 進位制詳解:二進位制、八進位制和十六進位制
- 讓我們一起啃演算法----二進位制求和演算法
- 二進位制與二進位制運算
- JavaScript 二進位制、八進位制與十六進位制JavaScript
- (二進位制)
- 二進位制
- 十進位制——二 (八、十六 )進位制
- 二進位制,八進位制,十進位制,十六進位制的相互轉換
- 【進位制轉換】二進位制、十六進位制、十進位制、八進位制對應關係
- 二進位制、十進位制與十六進位制相互轉化
- java中二進位制、八進位制、十進位制、十六進位制的轉換Java
- 二進位制,八進位制,十進位制,十六進位制之間的轉換
- Python 進位制互相轉換(二進位制、十進位制和十六進位制)Python
- 計算機基礎進位制轉換(二進位制、八進位制、十進位制、十六進位制)計算機
- 二進位制轉十進位制快速方法
- 使用二進位制包來安裝MySQLMySql
- JAVA 二進位制,八進位制,十六進位制,十進位制間進行相互轉換Java
- 什麼是二進位制?二進位制如何轉換?
- 04 二進位制
- mysql二進位制日誌詳解MySql
- 大話二進位制,八進位制,十進位制,十六進位制之間的轉換
- JavaScript十進位制轉換為二進位制JavaScript
- Oracle二進位制與十進位制轉換Oracle
- 十進位制轉二進位制推導(草稿)
- [計算機基礎] 計算機進位制轉換:二進位制、八進位制、十進位制、十六進位制計算機
- 一看就懂二進位制、八進位制、十六進位制數轉換十進位制
- python進位制轉換(二進位制、十進位制和十六進位制)及注意事項Python
- Oracle中的二進位制、八進位制、十進位制、十六進位制相互轉換函式Oracle函式
- 進位制之間的轉換之“十六進位制 轉 十進位制 轉 二進位制 方案”
- 使用UltraEdit來拷貝貼上二進位制
- 整數轉化成八進位制、十六進位制、二進位制,以及轉回
- 演算法學習之二進位制的妙用演算法
- 十進位制與二進位制互相轉換指南
- 二進位制轉十進位制快速轉換方法
- 進位制與二進位制及相關轉換
- 位,位元組,二進位制,十六進位制間的關係
- 二進位制方式解決 power 問題
- Cocoapods 二進位制