数据结构和算法四(数组--数据统计)

204 阅读4分钟

此文章为学习笔记,非原创,侵删

数组中出现次数超过数组长度一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

思路

解法1

  • 新建一个对象object
  • 循环数组
  • objectkey为当前值,value为当前值存在的次数

时间复杂度为 O(n)

function MoreThanHalfNum_Solution(numbers){
  if (numbers && numbers.length > 0) {
    var length = numbers.length;
    var temp = {};
    for (var i = 0; i < length; i++) {
      if (temp['s' + numbers[i]]) {
        temp['s' + numbers[i]]++;
      } else {
        temp['s' + numbers[i]] = 1;
      }
      if (temp['s' + numbers[i]] > length / 2) {
        return numbers[i];
      }
    }
    return 0;
  }
}

解法2

  • 目标值的个数比其他所有值出现的次数之和多。例如题目中2出现的次数比1,3,5,4出现的次数之和要多
  • 符合要求的数一定会重复连续出现,例如题目中的2连续出现了3次
  • 记录两个变量:数组中的某个值target和次数count
  • 当前值和上次一遍历的值相等?次数+1 : 次数-1
  • count为0后target变为新的值(符合要求的数一定会重复连续出现,例如题目中的2连续出现了3次)
  • 遍历结束后保存的值,判断是否符合条件

时间复杂度为 O(n)

function MoreThanHalfNum_Solution(numbers) {
  if (numbers && numbers.length > 0) {
    var target = numbers[0];
    var count = 1;
    for (var i = 1; i < numbers.length; i++) {
      if (numbers[i] === target) {
        count++;
      } else {
        count--;
      }
      if (count === 0) {
        target = numbers[i];
        count = 1;
      }
    }
    count = 0;
    for (var i = 0; i < numbers.length; i++) {
      if (numbers[i] === target) count++;
    }
    return count > numbers.length / 2 ? target : 0;
  }
}

连续子数组的最大和

输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值,要求时间复杂度为O(n)

例如:[6,-3,-2,7,-15,1,2,2],连续子子数组的最大和为8(从第0个开始,到第3个为止)

思路

  • 记录当前连续子数组的最大值max默认值为数组第一项
  • 记录当前连续子数组累加值sum默认值为数组第一项
  • 从数组第二项开始遍历,判断sum的值
  • sum<0,则当前的sum不再向后边的累加,切设置 sum=当前值
  • sum>=0,则 sum=sum+当前值
  • summax,max=两者最大值

function FindGreatestSumOfSubArray(array) {
  if (Array.isArray(array) && array.length > 0) {
    let sum = array[0];
    let max = array[0];
    for (let i = 1; i < array.length; i++) {
      if (sum < 0) {
        sum = array[i];
      } else {
        sum = sum + array[i];
      }
      if (sum > max) {
        max = sum;
      }
    }
    return max;
  }
  return 0;
}

扑克牌顺子

扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。

2-10为数字本身,A为1,J为11...大小王可以看成任何数字,可以把它当作0处理。

思路

  • 数组排序,排序后数组变为有序数组。然后只需要查看大小王的个数是不是符合间隔数值的和即可
  • 遍历数组
  • 大小王作为0处理,记录0的个数
  • 记录所有数之间的间隔
  • 比较间隔数和大小王的个数是否相同
  • 如果相同则说明是顺子
  • 注意:连续出现两个相同的不为0的数字就不会是顺子了
function IsContinuous(numbers) {
    if (numbers && numbers.length > 0) {
        numbers.sort();
        let kingNum = 0;
        let spaceNum = 0;
        for (let i = 0; i < numbers.length - 1; i++) {
            if (numbers[i] === 0) {
                kingNum++;
            } else {
                const space = numbers[i + 1] - numbers[i];
                if (space == 0) {
                    return false;
                } else {
                    spaceNum += space - 1;
                }
            }
        }
        return kingNum - spaceNum >= 0;
    }
    return false;
}

第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回-1(需要区分大小写)

思路

解法1

  • 用一个object存储每个字符出现的次数,key为字符,value为次数
  • 遍历数组,存储次数生成object
  • 遍历object,找到第一个出现一次的字符

时间复杂度O(n) 空间复杂度O(n)

function FirstNotRepeatingChar(str) {
    if (!str) {
        return -1;
    }
    let countMap = {};
    const array = str.split('');
    const length = str.length;
    for (let i = 0; i < length; i++) {
        const current = array[i];
        let count = countMap[current];
        if (count) {
            countMap[current] = count + 1;
        } else {
            countMap[current] = 1;
        }
    }
    for (let i = 0; i < length; i++) {
        if (countMap[array[i]] === 1) {
            return i;
        }
    }
    return -1;
}

解法2

  • 使用js数组的方法indexOflastIndexOf
  • 遍历字符串,比较每个字符串第一次出现的位置和最后一次出现的位置是否相同
  • indexOf的时间复杂度为O(n),所以整体的时间复杂度为O(n2),空间复杂度为0。
function FirstNotRepeatingChar(str) {
      // write code here
      for (var i = 0; i < str.length; i++) {
        if (str.indexOf(str[i]) == str.lastIndexOf(str[i])) {
          return i;
        }
      }
      return -1;
}