LeetCode#345 反转字符串中的元音字母|Java HashSet和HashMap|双指针|String字符串和字符数组

1. 知识拓展

1.1 HashSet和HashMap

1.1.1 HashSet

HashSet是实现Set< E >接口的一个实体类,数据以哈希表的形式存放,特点是不允许有重复元素且无序存放元素。既然是实现了Set< E >接口,那Set< E >接口的特性是什么呢?

  • Set接口继承了Collection接口,故包含Collection接口的所有方法。
  • 无序(存储和取出顺序不一致,也有可能一致),但元素唯一,不允许有重复。
  • 实现类有HashSet,底层数据是哈希表;和TreeSet,底层数据是红黑二叉树。
    LeetCode#345 反转字符串中的元音字母|Java HashSet和HashMap|双指针|String字符串和字符数组_第1张图片
    如何初始化HashSet的值呢?
public static final String[] SET_VALUES = new String[] { "a", "b" };
public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES));
private final static HashSet<Character> vowels = new HashSet<>(
			Arrays.asList('a', 'e', 'o', 'i', 'u', 'A', 'E', 'O', 'I', 'U'));
HashSet<String> h = new HashSet<String>() {{
    add("a");
    add("b");
}};
HashSet<String> h = new HashSet<String>();
h.add("a");
h.add("b");

1.1.2 HashMap

HashMap是实现Map接口的一个实体类,它对键值做了一对一的映射关系,里面键值不能重复
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
LeetCode#345 反转字符串中的元音字母|Java HashSet和HashMap|双指针|String字符串和字符数组_第2张图片
HashMap的总体结构

LeetCode#345 反转字符串中的元音字母|Java HashSet和HashMap|双指针|String字符串和字符数组_第3张图片

1.1.3 HashSet和HashMap的区别

LeetCode#345 反转字符串中的元音字母|Java HashSet和HashMap|双指针|String字符串和字符数组_第4张图片

1.2 String字符串和字符数组

1.2.1 String字符串和字符数组的互相转换

字符数组转换为字符串

char[] array = new char[] {'a','b','c','d','e','f','g'};
String str = new String(array);
char[] array = new char[] {'a','b','c','d','e','f','g'};
String str2 = String.valueOf(array);

字符串转换为字符数组
使用toCharArray()方法

String msg = "i am a good boy!";
char[] dest = msg.toCharArray();

1.2.2 取String字符串中的某个元素

使用charAt()方法,s是String类型,p,q是int型的。

char s1 = s.charAt(p);
char s2 = s.charAt(q);

2.题目描述

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 1:
输入: “hello”
输出: “holle”

示例 2:
输入: “leetcode”
输出: “leotcede”

说明:
元音字母不包含字母"y"。

3.分析

使用双指针,一个指针从前往后遍历,一个指针从后往前遍历,遇到元音字母就交换位置。为快速判断一个字符是不是元音字符,将全部元音字母(包括大小写)添加到集合 HashSet 中,从而以 O(1) 的时间复杂度进行该操作。
时间复杂度:遍历所有的元素一次,O(n)
空间复杂度:只使用两个指针,O(1)

4.代码

public class ReverseVowels {

	//把所有的元音字母,包括大小写存到HashSet中
	private final static HashSet<Character> vowels = new HashSet<>(
			Arrays.asList('a', 'e', 'o', 'i', 'u', 'A', 'E', 'O', 'I', 'U'));
	
	public String reverseVowels(String s) {
		//字符串为空,直接返回null
		if(s == null)
			return null;
		char[] res = new char[s.length()]; //结果字符数组
 		int p = 0, q = s.length()-1; //双指针
		while(p <= q) {
			//取出指针对应的字符
			char s1 = s.charAt(p);
			char s2 = s.charAt(q);
			if(!vowels.contains(s1)) { //s1不是元音字母
				res[p++] = s1;
				//p++; 第一次提交后修改
			}
			else if(!vowels.contains(s2)) { //s2不是元音字母
				res[q--] = s2;
				//q--; 第一次提交后修改
			}
			else { //两指针对应元素至少有一个元音字母
				res[p++] = s2;
				res[q--] = s1;
			}
		}
		return new String(res);
    }
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String str = sc.nextLine();
		
		ReverseVowels rv = new ReverseVowels();
		System.out.println(rv.reverseVowels(str));
	}
}

5.运行结果

LeetCode#345 反转字符串中的元音字母|Java HashSet和HashMap|双指针|String字符串和字符数组_第5张图片
提交修改记录:

-把两个语句合成一个之后,运行更快了

res[p] = s1;
p++;

改为

res[p++] = s1;

参考网址

https://blog.csdn.net/zfliu96/article/details/83476493#21HashSet_111
https://blog.csdn.net/weixin_44551646/article/details/94898951
https://blog.csdn.net/cong____cong/article/details/79727938
https://includestdio.com/1375.html
https://blog.csdn.net/woshimaxiao1/article/details/83661464
https://blog.csdn.net/weixin_42153410/article/details/95494014

你可能感兴趣的:(LeetCode)