算法及思路(一)

目录

1.千分位

2.两数之和

3.最长不重复子串

4.罗马数字转换为整数

5.判断数字是否为回文数

6.Z字形变换

7.寻找两个有序数组的中位数

8.括号匹配 

9.电话号码的字母组合

10.盛水最多的容器​​


1.千分位

 思路:将参数转化为字符串,每次循环裁剪字符串的后三位加入返回值中
 主要用到的方法:String.slice(start,end); 裁剪字符串,不改变原字符串
 传参的方式: 1.无参:返回整个字符串
                        2.一参:从该位置(包括)到字符串的最后一位
                        3.二参:参数为起始(包括)到结束索引(不包括)

function toThousands(num) {
    var num = (num || 0).toString(), result = '';
    // 将传入数据转换为字符串
    while (num.length > 3) {
        // 只要字符串长度大于三就执行
        result = ',' + num.slice(-3) + result;
        // 将字符串后三位裁剪并加入最终的字符串     
        num = num.slice(0, num.length - 3);
        // 更新字符串长度
    }
    if (num) { result = num + result; }
    return result;
}
toThousands(1234567)  // '1,234,567'

 

用toLocaleString()方法实现  

 let num = new Number(123123123).toLocaleString()

 


 2.两数之和

输入一个数组及一个目标值,输出数组中相加之和等于目标值的两数的下标,多个匹配则用数组表示,用过的数字不能再用

twoSum([1,2,3,4,5,4,3,2,1],4)     // 输出 [[0,2],[1,7],[6,8]]

思路:遍历数组,每个遍历过的数字都添加到对象中,用对象判断该数字是否已使用过

function twoSum(nums, target) {
    let { num = [] } = { num: nums };
    // 容错处理
    let arr = [];
    let noObj = {};
    for (let i = 0; i < num.length; i++) {
        if (noObj[i]) {
            // 如果该下标已使用则跳出本次循环
            continue
        }
        for (let j = i + 1; j < num.length; j++) {
            if (noObj[j]) {
                continue
            }
            if (num[i] + num[j] == target) {
                // 如果有多个匹配项添加到数组中
                arr.push([i, j])
                // 将已使用下标保存到对象
                noObj[i] = i;
                noObj[j] = j;
                break
            }
        }
    }
    return arr;
};

 3.最长不重复子串

输入字符串,输出字符串中最长不重复子串的长度

思路: 移动窗口(数组),用对象记录字符及其下标,有相同的则移动左侧游标,保持三个数,left,right,num

            [a,b,c],b,b 没有相同的,用对象记录每个字符出现的位置 --- {a:0,b:1,c:3} --- 更新计数器mex(num,(right - left))

            [a,b,c,b],b --- a,b,[c,b],b 出现了相同的字符时将左侧游标右移至已出现字符下标+1的位置

function lengthOfLongestSubstring(s) {
    let num = 0, obj = {}, left = 0;
    if (!s) return 0
    if (s.length === 1) return 1
    for (let right = 0; right < s.length; right++) {
        // 有重复的或索引为0
        if (obj[s[right]] || obj[s[right]] == 0) {
            // 有重复的但是是在左游标之前
            if (obj[s[right]] < left) {
                obj[s[right]] = right
                console.log('true')
            } else {
                left = obj[s[right]] + 1
                obj[s[right]] = right
                console.log('false')
            }
        } else {
            // 无重复添加对应值
            obj[s[right]] = right
            console.log(left, right, obj, num)
        }
        num = Math.max(num, right - left + 1)
    }
    return num
}

 4.罗马数字转换为整数

 罗马数字只包括I - M

 思路:罗马数字计数从左往右依次相加,累加器 num,计数并返回,对象obj保存字母对应的数值

 判断当前位是否为: I | X | C , 有三种情况: 一.(I 为 V | X ) ; 二.(X 后可为 L | C); 三.(C 后可为 D | M)

function romanToInt(s) {
    let obj = {
        I: 1,
        V: 5,
        X: 10,
        L: 50,
        C: 100,
        D: 500,
        M: 1000
    },
        num = 0;
    for (let i = 0; i < s.length; i++) {
        if (s[i] == 'I') {
            if (s[i + 1] == 'V' || s[i + 1] == 'X') {
                num += obj[s[i + 1]] - obj[s[i]];
                i += 1
                continue;
            } else {
                num += obj[s[i]];
            }

        } else if (s[i] == 'X') {
            if (s[i + 1] == 'L' || s[i + 1] == 'C') {
                num += obj[s[i + 1]] - obj[s[i]];
                i += 1
                continue;
            } else {
                num += obj[s[i]];
            }
        } else if (s[i] == 'C') {
            if (s[i + 1] == 'D' || s[i + 1] == 'M') {
                num += obj[s[i + 1]] - obj[s[i]];
                i += 1
                continue;
            } else {
                num += obj[s[i]];
            }
        } else {
            num += obj[s[i]]
        }
    }
    return num;
};

 


 5.判断数字是否为回文数

 回文数:形如12321,逆转后相等

思路1:变成字符串,第一位与最后一位比较,如果第一位为符号直接为false

function isPalindrome(x) {
    var y = x + '',
        last = y.length - 1;
    for (let i = 0; i < Math.floor(y.length / 2); i++) {
        if (y[i] * 1 === NaN) {
            console.log('有符号')
            return false
        }
        if (!(y[i] == y[last])) {
            console.log('不是回文', [[y[i], y[last]]])
            return false
        }
        last -= 1;
    }
    return true
};

 

思路2:不用字符串实现:翻转数字与原数字比较

变量:reverse 为逆转后的数字 , rem 位数

翻转方法:( x / rem) % 10 获取当前待翻转位数值,将之前已翻转部分乘10后相加

                   x > x % rem)时循环

function isPalindrome(x) {
    if (x < 0) {
        return false
    }
    let reverseX = 0,
        log = 0,
        rem = 1;

    while (x > x % rem) {
        reverseX = reverseX * 10 + (Math.floor(x / rem) % 10)
        console.log(reverseX, rem, (Math.floor(x / rem) % 10))
        rem *= 10
    }

    return x == reverseX ? true : false;
}

 6.Z字形变换

输入:'12345678',3

输出:15246837

 1 5

 2 4 6 8

 3 7

 思路:控制方向记录每行的内容,当行数等于参数或等于1(不是第一次)时变换方向

三个变量,obj保存每行的内容 {行数:内容}

 turn为方向

 row为行数

 

function convert(s, numRows) {
        let obj = {},
            turn = 1, // 1为向下
            row = '1',
            reObj = '';
        if (numRows == 1) return s
        for (let i = 0; i < s.length; i++) {
            if (!obj[row]) {
                obj[row] = s[i]
            } else {
                obj[row] += s[i]
            }
            if (row == numRows || (row == 1 && typeof (row) != 'string')) {
                turn *= -1;
            }
            row *= 1;
            row += turn
        }
        for (const prop in obj) {
            reObj += obj[prop]
        }
        return obj
    };

 7.寻找两个有序数组的中位数

输入:[1,2,3] , [2,3,4]

输出:2.5

思路: 拼接数组,排序,如果数组长度为偶数取中间两数的平均值,为奇数则直接返回

用到的方法:array.concat()    array.sort()

sort方法可以接受一个函数作为参数,通过函数的返回值来控制升序或降序,升序:sort(function(a,b){return a - b})

function findMedianSortedArrays(nums1, nums2) {
        var ar1 = nums1.concat(nums2).sort(function(a,b){return a - b});
        console.log(ar1)
        if(ar1.length > 1) {
           if(ar1.length % 2 == 0) {
                return (ar1[ar1.length / 2] + ar1[ar1.length / 2 - 1]) / 2
            } else {
                return ar1[(ar1.length-1)/2]
            }
        }else {
            return ar1[0]
        }
    };

 


8.括号匹配 

匹配括号包括(), {}, []

思路: 将每一个左括号添加到数组,每遇到一个右括号就与数组的最后一位相比较,相同则pop数组,不同则返回false

 模拟栈

'([])'

x:['(','[']    // 遇到的第一个右括号(闭括号)与数组的最后一位比较

 

var isValid = function(s) {
    let obj = {
        '[' : 1,']' : 1,
        '(' : 2,')' : 2,
        '{' : 3,'}' : 3
    }
    let x = []
    for (let i = 0; i < s.length; i++) {
        if(s[i] == '(' || s[i] == '[' || s[i] == '{') {
            x.push(s[i])
        }else if(s[i] == ')' || s[i] == ']' || s[i] || '}') {
            if(x.length > 0) {
              if(obj[x[x.length-1]] == obj[s[i]]) {
                    x.pop()
                }else {
                    return false
                }
            }else {
                return false
            }
            
        }
    }
    if(x.length == 0) {
        return true
    }else {
        return false
    }
};

 


 9.电话号码的字母组合

键盘对应字母,1为空

模拟九键键盘,输出所有可能的字母组合
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

思路:每一次的循环都是将当前位与下一位数字代表的字母集合交叉组合,那么每一次循环都以上一次组合之后的集合与下一位代表的字母集合进行组合即可

例:输入"234",将"23"可能的字母组合后用组合后的字符集合与4代表的字符集合进行组合

变量:两个数组,一个用来过渡,一个用来保存累加的字符集合

function letterCombinations (digits) {
            let obj = {
                1: [''],
                2: ['a', 'b', 'c'],
                3: ['d', 'e', 'f'],
                4: ['g', 'h', 'i'],
                5: ['j', 'k', 'l'],
                6: ['m', 'n', 'o'],
                7: ['p', 'q', 'r', 's'],
                8: ['t', 'u', 'v'],
                9: ['w', 'x', 'y', 'z']
            }
            if(digits == '') return []
            let newArr = [];
            let oldArr = obj[digits[0]];
            var i = 1
            while (i < digits.length) {
                for (let x = 0; x < oldArr.length; x++) {
                    for (let y = 0; y < obj[digits[i]].length; y++) {
                        newArr.push(oldArr[x] + obj[digits[i]][y])
                    }
                }
                oldArr = newArr.slice();
                newArr = []
                i++
            }
            return oldArr
        };

 


 10.盛水最多的容器

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

输入: [1,8,6,2,5,4,8,3,7]
输出: 49

思路:另一种移动窗口

用两个游标,分别从最左侧和最右侧开始,每次将最小的边向中间移动一格,记录最大的面积

function maxArea(height) {
    for (let i = 0, j = height.length - 1; i != j; height[i] < height[j] ? i++ : j--) {
        indexLength = j - i;
        minHeight = height[i] > height[j] ? height[j] : height[i];
        maxValue = indexLength * minHeight > maxValue ? indexLength * minHeight : maxValue;
    }
    return maxValue
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值