7. <tag-数组和哈希表>-lt.73-矩阵置零 + lt.1464-数组中两元素的最大乘积 + lt.169-多数元素 2.1(摩尔投票法) 1.6
lt. 73 矩阵置零
本题同, 面试题 01.08. 零矩阵
[案例需求]
[思路分析]
- 第一次双重循环遍历矩阵(二维数组), 使用两个hashSet记录下0的行数和列数, 为什么用Set集合, 因为set集合内的数据无序不可重复, 去重;
- 第二次双重循环遍历矩阵, 如果矩阵此时的行号i 或列号j 有一个被包含在上面的那两个集合中了, 把 matrix[i][j] 置为0即可;
- 这种思路的空间复杂度 O(m + n);
[代码实现]
class Solution {
public void setZeroes(int[][] matrix) {
// 建立两个集合分别存储矩阵中0的行标和列标
// 在这里我们选用set是为了去重, 因为矩阵中是很可能同一行或同一列有多个0的
Set<Integer> rowSet = new HashSet<>();
Set<Integer> colSet = new HashSet<>();
//遍历矩阵(二维数组),记录行标, 列标
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[i].length; j++){
if(matrix[i][j] == 0){
rowSet.add(i);
colSet.add(j);
}
}
}
//置零
//再次遍历, 只要是发现下标跟前面记录的为0的行标/列标相关的, 一律置为0
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[i].length; j++){
if(rowSet.contains(i) || colSet.contains(j))
matrix[i][j] = 0;
}
}
}
}
优化版本–利用数组中第一行和第一列作为标志位
思路:
用第一行、第一列置零表示这行、列需要置零,由于后面的元素为 0,前面的没有置零到,所以要再重复一次。 然后第一行和第一列需要特判,因为上面遍历其它行列时,第一行第一列经过了更改,所以要在最先就遍历一下,是不是第一行或第一列有 0(开个变量)。 最后第一行列遍历记录结束后,开始两次遍历其它行列更改,再最后更改第一行列即可。
class Solution {
public void setZeroes(int[][] matrix) {
int row = matrix.length;
int col = matrix[0].length;
boolean row0_flag = false;
boolean col0_flag = false;
// 第一行是否有零
for (int j = 0; j < col; j++) {
if (matrix[0][j] == 0) {
row0_flag = true;
break;
}
}
// 第一列是否有零
for (int i = 0; i < row; i++) {
if (matrix[i][0] == 0) {
col0_flag = true;
break;
}
}
// 把第一行第一列作为标志位
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
// 置0
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
if (row0_flag) {
for (int j = 0; j < col; j++) {
matrix[0][j] = 0;
}
}
if (col0_flag) {
for (int i = 0; i < row; i++) {
matrix[i][0] = 0;
}
}
}
}
lt.1464-数组中两元素的最大乘积
[案例需求]
[思路分析]
- 这道题很简单, 通过Arrays.sort(nums), 对数组排序后, 直接取数组的最后两位, 然后返回 两个数分别-1后的乘积即可;
- 但是, 这种解法的时间和空间复杂度仍然不够好;
- 我们可以使用下面这种思路, 能够达到 100% 100%的效果:
- 定义两个数, 一个最大值, 一个次大值;
- 对数组遍历一次, 当每次找出大于最大值的时候, 先把这个最大值赋给次大值, 然后把这个大于最大值的数替换成最大值即可;
- 如果这个数小于最大值, 但大于次大值, 那么把这个值替换为次大值即可;
[代码实现]
class Solution {
public int maxProduct(int[] nums) {
// //对数组进行排序
// Arrays.sort(nums);
// return (nums[nums.length-1]-1) * (nums[nums.length-2]-1);
int max = 0;
int maxLess = 0;
//遍历一次
for(int i = 0; i < nums.length; i++){
if(nums[i] > max){
maxLess = max;
max = nums[i];
}else if (nums[i] > maxLess){
maxLess = nums[i];
}
}
return (max-1) * (maxLess-1);
}
}
lt.169-多数元素(摩尔投票法)
[案例需求]
[思路分析]
[代码实现]
class Solution {
public int majorityElement(int[] nums) {
//集合存储(k-v)-->(具体的数-次数)
//为什么用集合? 因为给定的数是唯一的, 可以作为key, 而出现次数是不唯一的, 利用集合可以很方便的根据给定义的数(key), 给出出现的次数(value)
Map<Integer,Integer> hashMap = new HashMap<>();
//遍历给定数组
for(int i =0; i < nums.length; i++){
if(hashMap.containsKey(nums[i])){
hashMap.put(nums[i], hashMap.get(nums[i]+1));
}else{
hashMap.put(nums[i], 1);
}
}
//遍历数组, 比较数组中的哪一个数在集合中记录的出现次数 > 数组长度/2
// 返回的是集合的key
for(int num : nums){
if(hashMap.get(num) > nums.length/2)
return num;
}
return -1;
}
}
[解法2]
class Solution {
public int majorityElement(int[] nums) {
//法一, 排序后,找中间值, 多的一般都会跨过或等于中间值
Arrays.sort(nums);
return nums[nums.length/2];
}
}
[解法3相对最优解 摩尔投票法
]
class Solution {
public int majorityElement(int[] nums) {
//法二,
//摩尔投票法
//从第一个数开始count=1,
//遇到相同的就加1,
//遇到不同的就减1,
//减到0就重新换个数开始计数,总能找到最多的那个
int count = 1;
int res = nums[0];
for(int i = 1; i < nums.length; i++){
if(res == nums[i]){
++count;
}else{
--count;
if(count == 0){
count = 1;
res = nums[i];
}
}
}
return res;
}
}
补充:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)