目录
- 前言
- 问题介绍
- 解决方案
- 代码编写
- java语言版本
- c语言版本
- c++语言版本
- 思考感悟
- 写在最后
前言
当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~
在此感谢左大神让我对算法有了新的感悟认识!
问题介绍
原问题
给定字符串chars,两个字符char1,char2,求在chars中,char1和char2之间的最短距离
如:
chars = [1,3,3,3,2,3,1], char1 = 1, char2 = 2
结果为:2
进阶问题
在原问题的基础上,牺牲空间复杂度,换取时间复杂度,并且能够做到任何char1和char2之间的最短距离获取复杂度为O(1)
解决方案
原问题:
1、首先申请两个变量index1,index2。index1代表最近一次找到char1的index,index2代表最近一次找到char2的index
2、每一次找到char1和char2时更新index1和index2,然后计算一次index1和index2之间的距离,找到最小值即可。
进阶问题
1、申请一个map,key为Char类型,value为Map类型,value的mapkey为char类型,value为Integer类型,即Map<Character,Map<Character,Integer >
2、遍历chars,每新增一个chars[i]时,更新char[0… i]的所有key,重新计算与chars[i]之间的距离
空间复杂度:O(n^2) ,查询时间复杂度O(1)
代码编写
java语言版本
原问题:
/**
* 二轮测试:问题一
* @return
*/
public static int minDisCp1(char[] chars, char c1, char c2) {
if (chars == null || chars.length == 0) {
return -1;
}
if (c1 == c2) {
return 0;
}
// c1 最近出现的位置
int last1 = -1;
// c2 最近出现的位置
int last2 = -1;
int min = Integer.MAX_VALUE;
for (int i = 0; i < chars.length; i++) {
if (chars[i] != c1 && chars[i] != c2) {
continue;
}
if (chars[i] == c1) {
last1 = i;
if (last2 != -1) {
min = Math.min(min,i - last2);
}
}
if (chars[i] == c2) {
last2 = i;
if (last1 != -1) {
min = Math.min(min, i - last1);
}
}
}
return min == Integer.MAX_VALUE ? -1 : min;
}
进阶问题
public static void main(String[] args) {
//System.out.println(minDisCp1(new char[]{'1', '3', '3', '3', '2', '3', '1'}, '1', '2'));
MinDistanceCp2 minDistanceCp2 = new MinDistanceCp2(new char[]{'1', '3', '3', '3', '2', '3', '1'});
minDistanceCp2.getMinDis('1', '2');
}
/**
* 进阶问题使用工具类实现
*/
public static class MinDistanceCp2{
private Map<Character, Map<Character, Integer>> map;
public MinDistanceCp2(char[] chars) {
this.map = new HashMap<>();
init(chars);
}
/**
* 初始化统计最短距离填充map
* @param chars
*/
private void init(char[] chars) {
if (chars == null || chars.length == 0) {
return;
}
for (int i = 0; i < chars.length; i++) {
if (!map.containsKey(chars[i])) {
map.put(chars[i], new HashMap<>());
// 距离自己是0
map.get(chars[i]).put(chars[i], 0);
}
dealChar(chars, i);
}
}
/**
* 遍历所有数组,更新最近距离
* @param index
* @Param chars
*/
private void dealChar(char[] chars, int index) {
for (int i = 0; i < index; i++) {
int dis = index - i;
Map<Character, Integer> mapI = this.map.get(chars[i]);
Map<Character, Integer> mapIndex = this.map.get(chars[index]);
// 更新i处的
if (mapI.get(chars[index]) == null || mapI.get(chars[index]) > dis) {
mapI.put(chars[index], dis);
}
// 更新index
if (mapIndex.get(chars[i]) == null || mapIndex.get(chars[i]) > dis) {
mapIndex.put(chars[i], dis);
}
}
}
/**
* 获取最短距离
* @param c1
* @param c2
* @return
*/
private int getMinDis(char c1, char c2) {
if (map.get(c1) == null || map.get(c2) == null) {
return 0;
}
return map.get(c1).get(c2) == null ? -1 : map.get(c1).get(c2);
}
}
c语言版本
正在学习中
c++语言版本
正在学习中
思考感悟
这道题表面上是计算字符串中的最短距离,实际上可以抽象到工具类,字符可以变为泛型,我们可以使用这个思想计算任何对象数组中两个对象之间的最短距离,业务也会有此需求的。
还有一点需要注意的就是,这里HashMap对于8大基本变量由于jvm常量池和装箱拆箱的操作,我们可以直接对常量进行put,而使用对象作为key的时候,可能会出现你认为相等的两个对象(值相等)但是却能够同时存在于map中作为两个key存在。原因是因为hashmap判断key是否相等的逻辑是:
1、首先通过hash值(这里hash不是hashcode,是高16位和低16位的异或结果)找到Node列表tab的坐标,也就是数组中的头结点,如果p为null,则直接630行,表示该桶是空桶。
2、如果不为null说明该桶有值了,这个时候判断key存在的逻辑在633和634行,说明先比较hash相等(冲突)并且Node对象中的key地址相等或者equals为true(可以重写)时两个对象相等。
因此如果我们使用对象作为key,不同的对象,但是值相同,需要重写equals和hashcode,必须重写hashcode才能通过633行的判断,这也就是为什么面试中经常问到的一个问题:equals重写,hashcode为什么一定要重写?
后面会有一篇关于java基本数据结构的源码解读,欢迎大家前来指导~
写在最后
方案和代码仅提供学习和思考使用,切勿随意滥用!如有错误和不合理的地方,务必批评指正~
如果需要git源码可邮件给2260755767@qq.com
再次感谢左大神对我算法的指点迷津!