代码随想录Day06| 有效的字母异位词 两个数组的交集 快乐数 两数之和
1.题目链接:有效的字母异位词 - 力扣
题目描述:给定两个字符串 *s*
和 *t*
,编写一个函数来判断 *t*
是否是 *s*
的字母异位词。
**注意:**若 *s*
和 *t*
中每个字符出现的次数都相同,则称 *s*
和 *t*
互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
解题思路:
开辟一个整型数组a存储字母az,因为az的ASCII是连续排列的,所以它们可以按照一定的数字规律储存在数组a里面,0代表a,1代表b,以此类推。然后使用for循环。首先遍历字符串s,出现相应的字母,就在对应的字母下标上加上1。再开辟了一个数组b存储字母a~z,和上面所讲的一样,最后比较ab两个数组的大小,出现了不一样的数字则返回false,没有不一样的,循环完则返回true。
后面在学习的时候发现自己和代码随想录中的思路差不多,但还是多开辟了一个数组,其实可以一加一减,在字符串s中出现的就在数组对应的字母下标中+1,字符串t中出现的就在数组对应的字母下标中-1。最后和0进行比较,不是0就说明t和s不互为字母异位词。这个方法还是很巧妙的,节省了空间。
下面是代码示例:
(开辟了两个数组的):
class Solution{
public boolean isAnagram(String s, String t) {
int[] a=new int[26];
int[] b=new int[26];
char[] charS=s.toCharArray();
char[] charT=t.toCharArray();
int lenS=s.length();
int lenT=t.length();
if(s.length()!=t.length()){
return false;
}
for(int i=0;i<lenS;i++){
a[charS[i]-'a']++;
b[charT[i]-'a']++;
}
for(int i=0;i<26;i++){
if (a[i] != b[i]) {
return false;
}
}
return true;
}
}
(使用一加一减,只开辟了一个数组的):
class Solution{
public boolean isAnagram(String s, String t) {
int[] record=new int[26];
for(int i=0;i<s.length();i++){
record[s.charAt(i)-'a']++;
}
for(int i=0;i<t.length();i++){
record[t.charAt(i)-'a']--;
}
for(int count:record){
if(count!=0){
return false;
}
}
return true;
}
}
2.题目链接:两个数组的交集 - 力扣
题目描述:给定两个数组 nums1
和 nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
文章讲解/视频讲解:https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html
解题思路:
之前对哈希没有很了解,所以在做这道题的时候完全没有想到用哈希。主要是我对于java使用哈希的语法还没掌握的很好,后面多花点时间学习。
1.暴力解法:
因为力扣上面给了两个数组里面存储值的大小,所以可以开辟一个数组大小为1001的数组,然后根据所出现的数字,储存到对应的数组下标中去,如果不为0,则++,为1的话则是出现了重复的数字,就不用再++。对于nums2的话,则是遇见了对应的数组下标内储存的数为1的话就++,为1的话就不用++。同时使用一个count来记录出现了多少个重复的数字,用于后续需要返回的数组的大小
代码示例如下:
class Solution{
public int[] intersection(int[] nums1, int[] nums2){
int[] a=new int[1001];
int count=0;
for(int i=0;i< nums1.length;i++){
if(a[nums1[i]]==0){
if(a[nums1[i]]==1){
continue;
}
else a[nums1[i]]++;
}
}
for(int i=0;i< nums2.length;i++){
if(a[nums2[i]]==1){
if(a[nums2[i]]==2){
continue;
}
else {
a[nums2[i]]++;
count++;
}
}
}
int[] b=new int[count];
int j=0;
for(int i=0;i<1001;i++){
if(a[i]==2){
b[j++]=i;
}
}
return b;
}
}
2.使用HashSet(学习后)
题目中说明了:输出结果中的每个元素一定是唯一的,也就表示输出的结果没有重复的,而且不需要考虑输出结果的顺序,这个时候就可以考虑使用哈希表。使用HashSet可以将nums1中的出现过的元素构成一个无重复的元素的集合,接着再和nums2进行比较即可。
补充:HashSet是一个没有重复元素的集合,但是元素的顺序可能会随着时间的改变而改变。 创建HashSet对象 Set< > hs=new HashSet<>(); 添加元素 hs.add()(如果集合中有这个元素,则不会重复添加) 移除元素 hs.remove()
将集合转化为数组:
resSet.stream()
:将集合resSet转换为一个Stream流,使得我们可以对集合中的元素进行操作。mapToInt(x -> x)
:通过mapToInt方法,将Stream中的每个元素x映射为一个int值。在这里,每个元素都保持不变,即转换为自身。toArray()
:将Stream流中的元素收集到一个int类型的数组中,并返回该数组。
下面是代码示例:
class Solution3 {
public int[] intersection(int[] nums1, int[] nums2) {
if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
return new int[0];
}
Set<Integer> set1 = new HashSet<>();
Set<Integer> reSet = new HashSet<>();
//遍历数组
for (int i : nums1) {
set1.add(i);
}
//遍历数组2的过程中判断哈希表中是否出现了该元素
for (int i : nums2) {
if (set1.contains(i)) {
reSet.add(i);
}
}
return reSet.stream().mapToInt(x -> x).toArray();
}
}
3.题目链接:快乐数 - 力扣
题目描述:编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2:
输入:n = 2
输出:false
文章讲解/视频讲解:代码随想录 (programmercarl.com)
解题思路:
这道题的解题关键是对于无线循环的解读。题目中说了会无限循环,也就是说再求和的过程中,sum会重复出现,如果它开始重复出现了,那么就说明这个数不是快乐数。
当遇到了要快速判断一个元素是否在集合里面出现时,就需要考虑哈希法。
对于求和计算的方法较为简单,就不单独描述了。
下面是代码示例:
class Solution {
public boolean isHappy(int n) {
Set<Integer> record =new HashSet<>();
while (n!=1&&!record.contains(n)){
record.add(n);
n=getNextNumber(n);
}
return n==1;
}
private int getNextNumber(int n){
int sum=0;
while (n>0){
int temp=n%10;
sum+=temp*temp;
n=n/10;
}
return sum;
}
}
4.题目链接:
题目描述:给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
文章讲解/视频讲解:代码随想录 (programmercarl.com)
解题思路:
使用哈希表map,储存遍历过的元素。key储存数值,value储存对应的数组的下标。再遍历一个元素的时候,去map中寻找对应的目标元素是否之前遍历过,目标元素等于目标数值-当前遍历的元素的数值。如果map中有则取出来放到数组中并返回。
代码示例如下:
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res=new int[2];
if(nums==null||nums.length==0){
return res;
}
Map<Integer,Integer>map=new HashMap<>();
for(int i=0;i< nums.length;i++){
//遍历当前元素,并在map中寻找是否有匹配的key
int temp=target-nums[i];
if(map.containsKey(temp)){
res[1]=i;
res[0]=map.get(temp);
break;
}
map.put(nums[i],i );
}
return res;
}
}
总结:
今天的题目都不算很难。重点是理解哈希和学习哈希表。后续需要复习和回顾。今天所学习到的新的知识还是很多的。今天较忙,所以写的较为潦草。