常见算法题(一)

199 阅读4分钟

常见算法题(一)

(1) 用二维数组 matrix 代表一个正方形矩形阵,设计一个算法返回矩阵对角线元素的和。需要注意: 对角线交点的值只计算一次。

举例1.

const matrix = [
            [1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]
      ];
// 返回 25 ,也就是 1,3,5,7,9 相加。

举例2.

const matrix = [
            [1, 2, 3, 4],
            [5, 6, 7, 8],
            [9, 10, 11, 12],
            [13, 14, 15, 16]
      ];
// 返回 68 ,也就是 1,4,6,7,10,11,13,16 相加。
求和方法实现
// 常规思路
const sumMatDiagonalODR = (matrix) => {
// 这里的奇数正方形矩阵指的是一维数组元素个数是奇数还是偶数。
    try {
        const oddEvenArray = matrix.length % 2 === 0;
        let num = 0
        for (let i = 0; i < matrix.length; i++) {
            for (let j = 0; j < matrix[i].length; j++) {
                // 每一个二维数组遍历时都需要累加两个元素和(奇数正方形矩阵时,对角线交点除外)
                if(i === j) {
                    num += matrix[i][j];
                    // 当目前为奇数正方形矩阵,并且正在遍历中间的二维数组的中心元素(两对角线交点的元数)时,直接退出当前二维数组循环,执行下一个二维数组循环;
                    if(!oddEvenArray && Math.floor(matrix.length / 2) === i) {
                        continue;
                    }
                }
                if(matrix.length - 1 - i === j) {
                    num += matrix[i][j];
                }
            }
        }
        console.log('num', num);
        return num;
    } catch(err) {
        console.log(err);
    }
};

// 优化版本
const sumMatDiagonalOPT = (matrix) => {
    try {
        let num = 0;
        for (let i = 0; i < matrix.length; i++) {
            num += matrix[i][i] + matrix[i].at(-1 - i);
        }
        if (matrix.length % 2 !== 0) {
            const index = Math.floor(matrix.length / 2);
            num -= matrix[index][index];
        }
    console.log('num', num);
    } catch(err) {
        console.log(err);
    }
}

// 极简版
const sumMatDiagonalOPL = (matrix, num = 0) => !matrix.forEach((item, i) => num += matrix[i][i] + matrix[i].at(-1 - i)) && (matrix.length % 2 !== 0 ? (num -= matrix[Math.floor(matrix.length / 2)][Math.floor(matrix.length / 2)]) : num);

(2) 有数组arr,由不同整数组成,升序排列数组,,设计一个程序,满足返回arr[i] = i 的最小索引 i,没有的话返回-1。

举例1.

const arr = [1, 2, 2, 5, 4, 3]; 
// 升序排序后得 
arr === [1, 2, 2, 3, 4, 5];
arr[2] === 2, 返回 2

举例2.

const arr = [8, 48, 1365, 899, 34, 344, 2];
// 升序排序后得
arr === [2, 8, 34, 48, 344, 899, 1365];
以上不满足 arr[i] === i,返回 -1

实现

// 常规思路
const fiexdPointOne = (arr, num = -1) => {
    arr.sort((a, b) => a - b);
    for (let j = 0; j < arr.length; j++) {
        if(arr[j] === j) {
            return num = j;
        }
    }
    return num
}

// 优化版本
const fiexdPointTwo = (arr) => arr.sort((a, b) => a - b).findIndex((e, i) => i === e);
const arr = [4, 8, 7, 3, 9, 5, 6, 19, 8, 25, 28, 11, 99, 26, 38, 1, 2];
console.log(fiexdPointOne(arr)); // 8
console.log(fiexdPointTwo(arr)); // 8

(3) 判断字符串是否为回文串

举例1.

const str1 = 'abcdedg';
const str2 = 'abcdcba';
str1从左往右读与从右往左读不一致,故不是回文串。
str2从左往右读与从右往左读一致,是回文串。

实现

// 常规思路
const testPDString  = (str, boolean = true) => {
    if (typeof str !== 'string') return alert('请入参字符串');
    if (str.length <= 1) return boolean;
    for (let i = 0; i < Math.floor(str.length / 2); i++) {
        if (str[i] !== str.at(-1 - i)) {
            return boolean = false;
        }
    }
    return boolean;
}
console.log(testPDString('abcdefg', boolean)); // false
console.log(testPDString('abcdcba', boolean)); // true
console.log(testPDString('abcddcba', boolean)); // true

// 优化版本
const PDString = (str) => typeof str === 'string' ? !str.split('').some((ele, i) => ele !== str.at(-1 - i)) : alert('请入参字符串');
console.log(PDString('abcdefg')); // false
console.log(PDString('abcdcba')); // true
console.log(PDString('abcddcba')); // true

(4) 扁平化数组并升序排序

举例1.

const arr = [2, 9, 13, [6, 8, 8, [223, 688, 725]], [34, 101, 555]];
// 扁平化数组并升序排序后得到
arr === [2, 6, 8, 8, 9, 13, 34, 101, 233, 555, 688, 725];

实现

// 数组扁平化
const deconstructArr = (arr) => {
    // 扁平化方式2
    return arr.flat(Infinity);
    
    // 扁平化方式2
    const len = arr.length;
    let newArr = [];
    for (let i = 0; i < len; i++) {
        if (Array.isArray(arr[i])) {
            newArr = [...newArr, ...deconstructArr(arr[i])]
            // newArr.push(...deconstructArr(arr[i]));
            // newArr = newArr.concat(deconstructArr(arr[i]));
        } else {
            newArr.push(arr[i]);
        }
    }
    return newArr;
}

// 1.冒泡排序
const bubblingSort = (arr) => {
    if (!Array.isArray(arr)) return;
    const newArr = deconstructArr(arr);
    const length = newArr.length;
    let num;
    for (let i = 0; i < length - 1; i++) {
        for(let j = 0; j < length; j++) {
            if (+newArr[j] > +newArr[j + 1]) {
                num = newArr[j];
                newArr[j] = newArr[j + 1];
                newArr[j + 1] = num;
            }
        }
    }
    return newArr
}


// 2.插入排序
const pushSort = (arr) => {
    if (!Array.isArray(arr)) return;
    const newArr = deconstructArr(arr);
    const newArr = [Arr[0]];
    let num;
    for (let i = 1; i < Arr.length; i++) {
        newArr.push(Arr[i]);
        for (let j = newArr.length - 1; j > 0; j--) {
            if (+newArr[j] < +newArr[j - 1] ) {
                num = newArr[j];
                newArr[j] = newArr[j - 1];
                newArr[j - 1] = num;
            }
        }
    }
    return newArr;
}

// 3.原生数组sort方法排序
const APIArraySort = (arr) => {
    if (!Array.isArray(arr)) return;
    return deconstructArr(arr).sort((a, b) => a - b);
}


const array = [[1, 4, 5, 9, 10, [646, 49, 46, 32, 89, 110], {a: 14, b: 'abc'}], [14,24,45,59,160]];
console.log(bubblingSort(array)); // [1, 4, 5, 9, 10, 646, 49, 46, 32, 89, 110, {a: 14, b: 'abc'}, 14, 24, 45, 59, 160]
console.log(pushSort(array)); // [1, 4, 5, 9, 10, 646, 49, 46, 32, 89, 110, {a: 14, b: 'abc'}, 14, 24, 45, 59, 160]
console.log(APIArraySort(array)); // [1, 4, 5, 9, 10, 646, 49, 46, 32, 89, 110, {a: 14, b: 'abc'}, 14, 24, 45, 59, 160]

(5) n个一组翻转数组

  • 给你一个数组,每n个元素为一组进行翻转,返回翻转后的数组
  • n是个正整数,它小于数组长度;如果n不是数组长度的因数,请将最后剩余的元素保持原有顺序

举例1.

const arr = [10, 20, 30, 40, 50, 60, 70]
// 每2个元素一组进行翻转
arr === [20, 10, 40, 30, 60, 50, 70]
// 每3个元素一组进行翻转
arr === [30, 20, 10, 60, 50, 40, 70]

实现

const reverseArrBatchFlip = (arr, n) => {
    // 每次翻转处理
    const handleArrEle = (arr, n, i) => {
        n--;
        let index = i + n / 2;
        let last = i + n; // 每轮翻转时,当前组的最后一个元素下标
        let step = 0; 
        for (let j = i; j < index; j++, step++) {
            let ele = arr[j];
            arr[j] = arr[last - step];
            arr[last - step] = ele;
        }
    };

    const newArr = [...arr]; 
    for (let i = 0; i < newArr.length; i++) {
        if (i % n === 0 && i + n < newArr.length || i === 0) {
            handleArrEle(newArr, n, i);
        }
    }
    return newArr;
};
reverseArrBatchFlip(arr, 4); // [79, 16, 884, 25, 9, 84, 6446, 494, 646, 6, 4, 9, 48, 8, 13, 89, 101]
reverseArrBatchFlip(arr, 5); // [494, 79, 16, 884, 25, 4, 9, 9, 84, 6446, 8, 13, 89, 646, 6, 48, 101]
reverseArrBatchFlip(arr, 6); // [6446, 494, 79, 16, 884, 25, 646, 6, 4, 9, 9, 84, 89, 13, 8, 48, 101]
reverseArrBatchFlip(arr, 7); // [84, 6446, 494, 79, 16, 884, 25, 13, 89, 646, 6, 4, 9, 9, 8, 48, 101]