leetcode刷题记录 js算法与数据结构 基础篇(上)

立志做一个情感博主的程序员


WechatIMG30.jpeg

1 #### 反转字符串中的单词
给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
输入: "Let's take LeetCode contest"
输出: "s'teL ekat edoCteeL tsetnoc"

export default str => {
  // 1 将字符串切割成数组
  let arr = str.split(/\s+/g);
  // 2 然后再讲数据的每一项再切成数组[[abc], [bcd], [efg]]  从而利用数组的  reverse进行反转
  let result = arr.map(item => {
      return item.split('').reverse().join('')
  })
  return result.join(' ')
}
// 不懂split reverse join 和map方法的请自行百度

2 #### 计数二进制子串 (稍微有点复杂, 闲麻烦的直接跳过)
给定一个字符串 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”字符。

规律图

image.png

位运算符链接 不懂自己吸纳哦 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

var countBinarySubstrings = function(s) {
    let matchFn = (str) => {
        // 找出一边相同的数字
        let startNum = str.match(/^(1+|0+)/)[0];
        // ^ 不懂看官方解释    对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
        let endNum = (startNum[0] ^ 1).toString().repeat(startNum.length);
        // startNum[0] 这里说一下 为什么要取[0], 因为 ^ 操作符比较的事 比特位
        // 比特(位):英文bit,是计算机晶体管的一种状态(通电与断电).就是0与1,真与假,是计算机最基本的传输单位.
        // 所以只取一位
        let target = `${startNum}${endNum}`
        // 注意 只能从字符串的最开始匹配  。
        // 或者用正则完成 let regs = new RegExp(`^(${startNum}${endNum})`); return regs.test(str) ? `${startNum}${endNum}` : ''; 但是如果数字(比特位太多 动态生成的正则会爆)
          if (str.slice(0, target.length) === target) {
            return `${startNum}${endNum}`;
        }
        return '';
    };

    let arr = [];
    for(i = 0; i < s.length - 1; i++) {
        let match = matchFn(s.slice(i));
        if (match) {
            arr.push(match);
        }
    }
    return arr.length;
};
countBinarySubstrings('00110011');

3#### 电话号码的字母组合
示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

1562230212545.jpg
var letterCombinations = function (digits) {
    // 存放数字对应的字母 
    let arr = ['', 1, 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz'];
    let newDigits = digits.split('');
    // 输入数字 所对应的字母  比如输入'23' => ['abc', 'def']
    let proveArr = newDigits.map(index => {
        return arr[index];
    });

    // 如果输入为'', 则返回[]
    if (!digits) {
        return [];
    }
    // 如果输入的是个位数 则直接返回
    else if (digits.length === 1) {
        return proveArr[0].toString().split('');   
    }
    else {
        let fn = proveArr => {
            let endResult = [];
            // 第三步 需要便利proveArr, 让每一个字母进行组合
            for (let i = 0; i < proveArr[0].length; i++) {
                for (let j = 0; j < proveArr[1].length; j++) {
                    endResult.push(`${proveArr[0][i]}${proveArr[1][j]}`);
                }
            }
            // 这一步很关键, 每次合并数组的前两组字母, 然后再递归  直到数组长度只剩下1
            proveArr.splice(0, 2, endResult);
            if (proveArr.length > 1) {
                fn(proveArr);
            }
            else {
                return endResult;
            }
            return proveArr[0];
        };
        return fn(proveArr);
    }  
};

4: #### 重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 "ab" 重复两次构成。

示例 2:
输入: "aba"
输出: False

示例 3:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

var repeatedSubstringPattern = function(s) {
    // 正则一步到位, 补货括号, 不了解此正则用法的自己去百度 (下边贴图)
    var reg = /^(\w+)\1+$/;
    return reg.test(s);
};
WechatIMG4119.png

5: #### 按奇偶排序数组 II
给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。
对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。
你可以返回任何满足上述条件的数组作为答案

示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。

var sortArrayByParityII = function(arr) {
     arr = arr.sort((a, b) => a - b);
    let odd = 1;
    let event = 0;
    let r = [];
    arr.forEach(item => {
        if (item % 2 === 0) {
            r[event] = item;
            event += 2;
        } else {
            r[odd] = item;
            odd += 2;
        }
    })
    return r;
};

6: #### 种花问题
假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花),和一个数 n 。能否在不打破种植规则的情况下种入 n 朵花?能则返回True,不能则返回False。

示例 1:
输入: flowerbed = [1,0,0,0,1], n = 1
输出: True

示例 2:
输入: flowerbed = [1,0,0,0,1], n = 2
输出: False

var canPlaceFlowers = function (flowerbed, n) {
    // 如果是n = 0, 或者 只有 flowerbed = [0]
    if (!n || (flowerbed.length === 1 && flowerbed[0] === 0)) {
        return true;
    }
    // 将所有的树坑 切为数组
    var arr = flowerbed.join().split(/,?1,?/);
    if (!arr) {
        return false;
    }
    var maxArr = 0;
    arr.forEach((item, ind) => {
        if (item.length) {
            maxArr += fn(item, ind);
        }
    });
   // 去查询数组里的每一组树坑做多可以种多少树
    function fn(value, ind) {
        var len = value.replace(/,/g, '').length;
        // 种最多树的 规律
        var maxNum = Math.round((len - 2) / 2);
        // 处理边界问题
        if ((ind === 0 || ind === arr.length - 1) && value.length >= 2) {
            return maxNum + 1;
        } else {
            return maxNum;
        }
    }
    return maxArr >= n;
};

排序类

7: 冒泡排序
冒泡排序算法运作原理:
1: 比较相邻的元素。如果第一个比第二个大,就交换他们两个
2: 针对所有的元素重复以上的步骤,除了最后一个。

// 外层循环控制右边界
for (let i = arr.length - 1, num; i > 0; i--) {
        // 内层循环控制左边界
        for (let j = 0; j < i; j++) {
            num = arr[j];
            if (num > arr[j + 1]) {
                arr[j] = arr[j + 1];
                arr[j + 1] = num;
            }
        }
    }

8: 选择排序
工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完

    for (let i = 0, num; i < arr.length; i++) {
            num = arr[i];
            for (let j = i + 1; j < arr.length; j++) {
                if (arr[j] < num) {
                    let prove = num;
                    num = arr[j];
                    arr[j] = prove;
                }
            }
            arr[i] = num;
        }

9: 快速排序
数组中制定一个元素作为标尺,然后跟数组每一项做对比, 比它大的放元素后边, 小的放它前边, 如此利用递归重复, 直至全部正序排列

快速排序 - 基础算法

缺点, 因为需要新开辟空间left right, 去存储元素, 所以导致不必要的空间损耗,造成空间复杂度增大

function quickSort(arr) {
    // 思路 从数组当中取出来一个值, 然后依次跟数组的每一项做对比, 小的放左边, 大的放右边
    // 目标元素
    let flag = arr[0];
    let left = [];
    let right = [];
    if (arr.length < 2) {
        return arr;
    } else {
        for (let i = 1, len = arr.length, tem; i < len; i++) {
            tem = arr[i];
            if (tem < flag) {
                left.push(tem);
            }
            else {
                right.push(tem);
            }
        };
        return [...quickSort(left), arr[0], ...quickSort(right)];
    }
};

快速排序 - 高级算法(in-place) 利用就地排序, 在原数组上进行换位操作

function inPlace(arr) {
    // 转换位置
    let swap = (arr, i, j) => {
        let tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    };
    // 找中间数下标 并且操作换位
    let findCenter = (arr, l, r) => {
        let flag = arr[l];
        // index 记载需要调换位置的下标
        let index = l + 1;
        for (let i = index; i <= r; i++) {
            if (arr[i] < flag) {
                // 如果找到比flag小的数字 就调换位置
                swap(arr, index, i);
                index++;
            }
        }
        swap(arr, l, index - 1);
        return index;
    };
    // 递归调用
    let sort = (arr, l, r) => {
        if (l < r) {
            // 中间位数的下标
            let cindex = findCenter(arr, l, r);
            sort(arr, l, cindex - 1);
            sort(arr, cindex, r);
        }
    };  
    sort(arr, 0, arr.length - 1);
    return arr;
}

9 : #### 最大间距
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。

示例 1:
输入: [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。

示例 2:
输入: [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。

var maximumGap = function(arr) {
        if (arr.length === 1 || arr.length === 0) {
            return 0;
        }
        // 冒泡排序
        let len = arr.length - 1;
        let num = null;
        let space = 0;
        for (let i = len; i > 0; i--) {
            for (j = 0; j < i; j++) {
                if (arr[j] > arr[j+1]) {
                    num = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = num;
                }
            }
            let reduce = arr[j+1] - arr[j]
            if (reduce > space) {
                space = reduce;
            }
        }
        return Math.max(space, arr[1] - arr[0]);
    };

10: #### 缺失的第一个正数
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。

示例 1:
输入: [1,2,0]
输出: 3

示例 2:
输入: [3,4,-1,1]
输出: 2

示例 3:
输入: [7,8,9,11,12]
输出: 1

// 方法1 直接使用sort排序  但会造成多余的循环 浪费性能
var firstMissingPositive = function (nums) {
    // 1 筛选出来 正整数
    let newArr = nums.filter(item => item > 0);
    // 2 排序 - 升序
    newArr.sort((a, b) => a - b);
    if (newArr[0] !== 1) {
        return 1;
    } else {
        for (let i = 0, len = newArr.length - 1; i < len; i++) {
            if (newArr[i + 1] - newArr[i] > 1) {
                return newArr[i] + 1;
            }
        }
        return newArr.pop() + 1;
    }
};

// 其实最优化的是我们在排序过程中就已经可以去找寻 差值, 所以接下来我们自己去写选择排序, 然后在排序内部, 这样便会减少一层循环
var firstMissingPositive = function (nums) {
    // 1 筛选出来 正整数
    let newArr = nums.filter(item => item > 0);
    // 2 排序 - 选择排序
    // newArr.sort((a, b) => a - b);
    let len = newArr.length;
    for (let i = 0, num; i < len; i++) {
        num = newArr[i];
        for (let j = i + 1; j < len; j++) {
            if (num > newArr[j]) {
                let c = num;
                num = newArr[j];
                newArr[j] = c;
            }
        }
        newArr[i] = num;
        // 判断i 是否大于 0
        if (i > 0) {
            if (newArr[i] - newArr[i - 1] > 1) {
                return newArr[i - 1] + 1;
            }
        } else {
            if (num === 0) { continue; }
            if (num !== 1) {
                return 1;
            }
        }
    }
    return newArr.length ? newArr.pop() + 1 : 1;
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容