算法打卡第五天

91 阅读3分钟

问题

  1. 剑指 Offer 04. 二维数组中的查找
  2. 剑指 Offer 11. 旋转数组的最小数字
  3. 剑指 Offer 50. 第一个只出现一次的字符

剑指 Offer 04. 二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

提议分析 判断有序的二位数组中是否存在某个值。 方法一: 本人第一次只想到了暴力破解发,即挨个遍历,找到就返回true,遍历完还没找到就返回false。

方法二: 看了一些其他解题思路,大概就找到这一种最快的,就是从右上角的数据开始遍历

  1. 数据排序规律 从左到右,从上到下依次增大数据
  2. 生变量row和column,初始化为右上角的索引
  3. 遍历数组,结束条件row小于一层数组长度,或者column < 0
  4. 如果目标值和这个相等则返回true,如果此值比目标值小则column -1,比目标值大则row+1
  5. 遍历完后还没找到则返回false
// 推荐线性查找
let row = 0;
let column = columnLength - 1;
while (row < rowLength && column >= 0) {
    console.log(row, column, matrix[row][column]);
    if (matrix[row][column] === target) {
        return true
    }
    if (matrix[row][column] > target) {
        column--;
    } else {
        row++
    }
}
return false

// 暴力 不推荐
// if (!matrix || !matrix.length || !matrix[0].length) {
//     return false
// }
// const length = matrix.length;
// const length1 = matrix[0].length;
// for (let i = 0; i < length; i++) {
//     for (let j = 0; j < length1; j++) {
//         console.log(i, j);
//         if (matrix[i][j] === target) {
//             return true
//         }
//     }
// }
// return false

剑指 Offer 11. 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

给你一个可能存在重复元素值的数组numbers,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组[3, 4, 5, 1, 2] 为 [1, 2, 3, 4, 5] 的一次旋转,该数组的最小值为1。

题意理解 旋转数组的最小元素

  1. 边间条件开始值小于结束值,直接返回开始值
  2. 初始化起始索引left=0,right=length -1
  3. 计算中间值,left值比之间值小则在左边,
  4. 计算中间值,right值比之间值小则在右边边,
  5. 因为存在重复的数据,所以开始位置和结束位置的数据可能相同
  6. 最后返回左侧的值
// 二分法
const length = numbers.length;
let left = 0;
let right = length - 1;
if (numbers[left] < numbers[right]) {
    return numbers[left]
}
while (left < right) {
    let mid = left + ((right - left) >> 1);
    if (numbers[mid] < numbers[right]) {
        right = mid;
    } else if (numbers[mid] > numbers[right]) {
        left = mid + 1;
    } else {
        right -= 1;
    }

}
return numbers[left]

// 暴力
const length = numbers.length;
let left = 0;
let right = length - 1;
if (numbers[left] < numbers[right]) {
    return numbers[left]
}
for (let i = 0; i < length - 1; i++) {
    if (numbers[i] > numbers[i + 1]) {
        return numbers[i + 1]
    }
}
return numbers[0]

剑指 Offer 50. 第一个只出现一次的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

提议理解 查找字符串中第一个只出现一次的字符,有则返回该字符,没有则返回" "。

  1. 遍历整个字符串,然后一次查找某个字符的首次出现和最后一次出现的位置,如果不相等则返回该字符,遍历完后返回一个空字符。
// 字符串自带方法
const length = s.length;
for (let i = 0; i < length; i++) {
    if (s.indexOf(s[i]) === s.lastIndexOf(s[i])) {
        return s[i]
    }
}
return " "

// Map 哈希表 比上面那种慢
const length = s.length;
let map = new Map()
for (let i = 0; i < length; i++) {
    if (map.has(s[i])) {
        map.set(s[i], 1)
    } else {
        map.set(s[i], -1)
    }
}
for (let i = 0; i < length; i++) {
    if (map.get(s[i]) === -1) {
        return s[i]
    }
}
return " "