题目描述
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
示例1
输入:nums = [3,2,3]
输出:3
示例2
输入:nums = [2,2,1,1,1,2,2]
输出:2
思路及实现
方法一
排序
思路: 在这里我们先将数组中的元素进行按非递减顺序排序,且下标为 ⌊ n/2 ⌋的元素一定为众数。则该元素就是最终结果。
实现:
具体代码实现:
当n为奇数时:
public class sort {
public static void main(String[] args) {
int[] arry = {3,2,3};
Arrays.sort(arry);
System.out.println("结果为:" + arry[arry.length/2]);
}
}/*结果为:3*/
数组上面的线表示如果众数是数组中的最最大值下标。
当n为偶数时:
public class sort {
public static void main(String[] args) {
int[] arry = {2,1,1,1,1,1,1,2,2,3};
Arrays.sort(arry);
System.out.println("结果为:" + arry[arry.length/2]);
}
}/*结果为:1*/
数组下面的线表示如果众数是数组中的最小值下标。
方法二
HashMap
思路: 我们使用哈希映射(HashMap)来存储每个元素以及出现的次数。对于哈希映射中的每个键值对,键表示一个元素,值表示该元素出现的次数。最后找出最大的值所对应的键即可。
实现:
具体代码实现:
public class doublePointer {
public static void main(String[] args) {
int[] arry = {2,2,1,1,1,2,2};
// 1.将基本类型的数组转换为对应包装类的数组
Integer[] arry1 = new Integer[arry.length];
//装箱操作
for (int i = 0; i < arry1.length; i++) {
arry1[i] = Integer.valueOf(arry[i]);
}
//2.将包装类数组元素放入哈希表,key表示元素值,value表示元素出现的次数
HashMap<Integer, Integer> times = new HashMap<>();
for (Integer i = 0; i < arry1.length; i++) {
Integer index = 0;
for (Integer j = 0; j < arry1.length; j++) {
if (Objects.equals(arry1[i], arry1[j])) {
index++;
}
}
times.put(arry1[i], index);
}
//遍历
for(Integer key : times.keySet()){
System.out.println("key: " + key + " value: " + times.get(key));
}
//3.找到出现次数最多的元素
//定义max记录最大的value值
Integer max = 0;
for (Integer Key : times.values()) {
max = Math.max(max, Key);
}
//定义result记录出现次数最多的元素值
Integer result = null;
Set<HashMap.Entry<Integer, Integer>> set = times.entrySet();
//该地图中包含的映射的集合视图
for (HashMap.Entry<Integer, Integer> entry : set) {
if (entry.getValue() == max) {
result = entry.getKey();
break;
}
}
System.out.println("结果为:" + result);
}
}/*
key: 1 value: 3
key: 2 value: 4
结果为:2
*/
下面我将对代码所用到的知识进行说明:
- 基本类型与封装类
Integer[] arry1 = new Integer[arry.length];
基本类型转为对应包装类,因为我们后续需要用到HashMap需要接收封装类类型。
区别:
- 封装类是引用类型。
基本类型在传递参数时都是按值传递,而封装类型是按引用传递的传递的是对象的地址。 - 存储位置
基本类型在内存中是存储在栈中,引用类型的引用(值的地址)存储在栈中,而实际的对象(值)是存在堆中。 - 默认值不同
基本类型跟封装类型的默认值是不一样的。例如int默认值0;Integer为null,因为封装类产生的是对象,对象默认值为null。
- 基本类型数组转为封装类数组
- 装箱操作
for (int i = 0; i < arry1.length; i++) {
/*基本类型的数组和对应包装类的数组虽然在语法上有所区别,但它们之间存在自动装箱和拆箱的特性,可以相互转换。*/
arry1[i] = Integer.valueOf(arry[i]);
}
- HashMap
HashMap(Map<? extends K,? extends V> m)
Interface Map<K,V>
参数类型
K - 由此地图维护的键的类型
V - 映射值的类型
k即为键key的类型 , v即为value的类型。
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
从中可以看出Map是HashMap的一个接口,实现类。
HashMap<Integer, Integer> times = new HashMap<>();
- equal
Objects.equals(arry1[i], arry1[j])
使用Objects.equals来进两个对象的比较比object.equal(object)更为安全,前者进行了非空判断,如果当调用equal的对象为null时第二种会报错。
- 增强型for循环
Java jdk5.0新增了foreach循环,用来遍历集合、数组等,这就是所谓的增强for循环。
for(集合元素的类型 局部变量 : 集合对象)
内部代码仍然调用迭代器
for(Object obj : coll){
System.out.println(obj);
}
-
public V get(Object key)
从HashMap get方法源码中可以看出返回的是键key对应的value值
public V get(Object key) {
Node<K,V> e;
return (e = getNode(key)) == null ? null : e.value;
}
- set接口
times.entrySet();返回set定义集合的类型HashMap.Entry<Integer, Integer>
Set接口Interface Set<E>
参数类型
E - 由此集合维护的元素的类型
Set<HashMap.Entry<Integer, Integer>> set = times.entrySet();
//该地图中包含的映射的集合视图
for (HashMap.Entry<Integer, Integer> entry : set) {
if (entry.getValue() == max) {
result = entry.getKey();
break;
}
}
收获
在解决这道简单算法题的路上,我通过查阅各种资料和文档了解了HashMap的基础知识和用法,增强for循环的用法, set接口等知识。学无止境,如果想要要彻底掌握,需要慢慢通过各种问题来复习发掘总结。
也认识到解决一个问题不能只持有一个正常的思路,从结果到问题本身未尝不是一个好的方法,知识的局限,限制了思考的方式,所以要多学习未知,复习