LeetCode学习之路01

2018-7-3

1.202_Happy_number

题目要求:

Write an algorithm to determine if a number is "happy".

A happy number is a number defined by the following process:Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.

转义:

给定一个数n,当n的各各位上的数字的平方和为1时则该数n为happy number.

若第一次计算结果不为1,继续利用该结果继续计算直到出现1,表示该数n为happy number,

或者出现重复的结果时,表示该数进入到了一个死循环,那么该数n将不可能是一个happy number。

遇到的问题:

​ 1.求出给定数n的各各数位:

​ 采用递归的方法求解。

    //传入数n,将数n的各位数存放到list集合中
    public  void getdigits(int n,List<Integer>list)
     {
         list.add(n%10);
         if(n<10)
         {
             return;
         }
         getdigits(n/10, list);
     }

​ 采用循环的方法求解。

    public void getNum(int n,List<Integer> list)
    {
        while(true)
        {
            list.add(n%10);
            if(n<10)
                return;
            n/=10;
        }
    }

整体求解思路:

​ 1.求出给定数n的各个位的数字,并将该数字存放到list集合中

​ 2.计算各位数字的平方和放入到另外一个存储结果的list集合中,

​ 为什么采用集合存储结果: 因为不知道要算多少次才能得出结果所以采用数组不合适, 又因为需要判断得出来的结果是否和以前的结果相同所以需要集合在存放之前的数据。

​ 3.由题目定义来看,如果给定数n第一次计算结果没有得1,就在利用该结果进行同样的计算。所以根据这样的特性我采用递归来进行计算。该递归的定义就是计算给定数,如果数的各个位数的平方和为1就返回true,如果陷入死循环(即出现与以前相同的结果)就返回false,如果上述两种情况都没发生就递归的进行下次计算。

代码:
public class Solution {
     private List<Integer> result=new ArrayList<>();
     public boolean isHappy(int n) {
            List<Integer> list=new ArrayList<Integer>();
            //取出n中各位数
            getdigits(n, list);
            int calculate = calculate(list,result);
            if(calculate==-1)
            {
                return false;
            }
            else if(calculate==1)
            {
                return true;
            }
            else 
            {
                return isHappy(result.get(result.size()-1));
            }
     }
     private int calculate(List<Integer> list, List<Integer> result) {
        //计算各各数的平方和并将数据存放到list集合中
        int sum=0;
        for (Integer integer : list) {
            sum+=integer*integer;
        }
        if(result.contains(sum))
        {
            //如果出现与list集合中的数相同的数则返回-1,
            return -1;
        }
        else if(sum==1)
        {
            //如果出现1返回1
            return 1;
        }
        else 
            //既没出现相同的也没出现1则返回0,表示继续下一轮计算
            result.add(sum);
            return 0;
        
    }
    public  void getdigits(int n,List<Integer>list)
     {
         list.add(n%10);
         if(n<10)
         {
             return;
         }
         getdigits(n/10, list);
     }
     @Test
     public void test() {
        int n=7;
        boolean happy = isHappy(n);
        System.out.println(happy);
    }

该问题分类:

单个数值->判断该数否满足给定要求

2.242_Valid_Anagram

题目要求:

​ Given two strings s and t , write a function to determine if t is an anagram of s.

​ anagram:如果一个字符串是由另一个字符串改变其字母排列顺序得到,则称这两个字符串为anagram

​ 如:anagram与nagaram Output:true

​ rat与car Output:false

转义:

​ 给定两个字符串,判断其中一个是否由另一个字符串改变元素排列顺序得到的。

整体求解思路:

​ 由题目可知:只要两个字符串中,所用的字符相同即可判定这两个字符串为anagram。所以我才用map集合才存储其中的一个字符串的每一个字符。map的key为字符串中的字符,value为该字符出现的频率。当存储完其中的某个字符串的时候遍历另外一个字符串。如果另外的字符串中的字符与当前map取出的字符(key)相同,则让当前字符出现的频率减少一(value),当频率减少到0时就将该元素从map中移出。如果出现了map中没有的元素则判断这两个字符串不是anagram。如果map完成遍历后,map为空则说明这两个字符串是anagram。

1.创建map,将其中的一个字符串存到map中,key存放每一个字符,value存放该字符出现的频率

2.遍历另一个字符串,如果其中的字符包含在map中,让map中该字符的频率减少1,如果该字符的频率减少到0,则从map中删除该字符。如果map中不包含遍历出来的字符则之间返回false。

3.当遍历完成后,map为空则返回true,不为空返回false

代码:
class Solution {
    public boolean isAnagram(String s, String t) {
        byte[] bytes = s.getBytes();
        Map<Byte,Integer> map=new HashMap<>();
        for(int i=0;i<bytes.length;i++)
        {
            Integer integer = map.get(bytes[i]);
            map.put(bytes[i],integer==null?1:integer+1);
        }
        byte[] bytes2 = t.getBytes();
        for(int i=0;i<bytes2.length;i++)
        {
            if(map.containsKey(bytes2[i]))
            {
                Integer integer = map.get(bytes2[i]);
                if(integer==1)
                {
                    map.remove(bytes2[i]);
                }
                else
                {
                    map.put(bytes2[i], integer-1);
                }
            }
            else
            {
                return false;
            }
        }
        if(map.isEmpty())
        {
            return true;
        }
        return false;
    }
该问题分类:

两个字符串->两个字符串的比较->判断两个字符串是否满足某种关系->两个字符串所用字符相同排列顺序不同

学习Discuss中的其他方案:
思路

1.由题目所知,两个字符串所使用的字符相同才满足要求。

2.所以利用长度为26的数组记录每一个字符出现的次数,与另一个进行对比。

3.如果相同返回true。

代码
public class Solution {
    public boolean isAnagram(String s, String t) {
        int[] alphabet = new int[26];
        for (int i = 0; i < s.length(); i++) alphabet[s.charAt(i) - 'a']++;
        for (int i = 0; i < t.length(); i++) alphabet[t.charAt(i) - 'a']--;
        for (int i : alphabet) if (i != 0) return false;
        return true;
    }
}
​

3.290_Word_Pattern

题目要求:

Given a pattern and a string str, find if str follows the same pattern.

Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.Notes:You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.

转义:

给定两个字符串,一个是模式串,一个是待匹配的字符串。模式串中是由26个小写英文字母组成。待匹配的字符串由英文单词组成,每个英文单词之间由空格相隔。如果待匹配串的模式与模式相同则返回true,否则返回false。

如:pattern:abba str :dog cat cat dog Output:true

​ pattern:aabb str:cat dog cat dog Output:false

整体求解思路:

1.模式串的长度应当和和待匹配串种的单词个数相同,所以首先判断如果不相同则肯定不符合返回false。

2.提取模式串,和待匹配串的规则。改规则为:记录哪几个位置上的字符或者单词相同。根据这个模式,map集合是最好的存储方式。key来存储字符或者单词,value是一个list集合用来存储该字符或者单词出现在字符串或字符数组中的哪几个位置。

3.如果模式串和待匹配的单词字符串能够匹配,则从他们两个提取出来的规则(map)的大小一致。如果不一致返回false

4.如果模式串和待匹配的单词字符串能够匹配,则他们两个的相对位置应当一致。例如a出现在模式串的1,3.则相同的单词也应当会在单词数组的1,3位置出现。遍历map集合得到map的value根据list集合去判断待匹配数组是否满足相对位置单词相同。如果不相同返回false

5.以上条件都满足返回true

代码:
//定义一个map,key为该数据,value为一个list集合存放该数据出现在当前字符串中的第几个位置上
public class Solution {
     public boolean wordPattern(String pattern, String str) {
         Map<Character, List<Integer>> map=new HashMap<>();
         String[] splitStr = str.split(" ");
         //如果模式串与带匹配的串的数组长度不一样,肯定不对
         if(pattern.length()!=splitStr.length)
         {
             return false;
         }
         //提取模式串的规则
         for(int i=0;i<pattern.length();i++)
         {
            List<Integer> list = map.get(pattern.charAt(i));
            if(list==null)
            {
                list=new ArrayList<>();
            }
            list.add(i);
            map.put(pattern.charAt(i), list);
            
         }
         //提取带匹配串的规则
         Map<String,List<Integer>> strMap=new HashMap<>();
         for(int i=0;i<splitStr.length;i++)
         {
             List<Integer> list = strMap.get(splitStr[i]);
             if(list==null)
                {
                    list=new ArrayList<>();
                }
                list.add(i);
                strMap.put(splitStr[i], list);
         }
         //如果两个map的大小不同则说明不满足规则返回false
         if(map.size()!=strMap.size())
         {
             return false;
         }
         for(Entry<Character, List<Integer>> entry:map.entrySet())
         {
             List<Integer> value = entry.getValue();
             String tmp=splitStr[value.get(0)];
             for(int i=1;i<value.size();i++)
             {
                 if(!tmp.equals(splitStr[value.get(i)]))
                 {
                     return false;
                 }
             }
         }
         return true; 
     }
     @Test
     public void test1(){
         String str1="abba";
         String str2="dog cat cat dog";
         boolean wordPattern = wordPattern(str1, str2);
         System.out.println(wordPattern);
     }
}
该问题分类 :

两个字符串->判断两个字符串是否满足某种关系->两个字符串是否保持相对位置和元素关系

学习Discuss中的其他方案:
思路:

1.寻找模式串与待匹配串的相对位置关系

2.该方法没有直接的去提取某一个串的相对位置关系,而是利用map中的input方法的返回值来建立了这种临时的对应关系。当两个字符串的这种临时的对应关系相同返回true否则返回false。为什么说是临时的对应关系呢,因为一旦循环结束我们将得不到这种对应关系。

3.使用条件:只用当两个元素不相同时才能使用这个方式判断对应关系。

​ 如:patter="ab" str="c a";

​ 应当返回true;其结果会返回false;

​ 可以通过不同的类型来解决这一问题。例如将patter中的元素设置为字符,str中的元素设置为字符串。

代码:
     public boolean wordPattern(String pattern, String str) {
        String[] words = str.split(" ");
        if (words.length != pattern.length())
            return false;
        Map index = new HashMap();
        for (Integer i=0; i<words.length; ++i){
            Object put1 = index.put(pattern.charAt(i), i);
            Object put2 = index.put(words[i], i);
            if ( put1!=put2 )
                return false;
        }
        return true;
        }
     @Test
     public void test1(){
         String pattern ="aabb";
         String str="dog cat dog cat";
         boolean wordPattern = wordPattern(pattern, str);
     }
}
​

4.451_Sort_Characters_By_Frequency

题目要求

​ Given a string, sort it in decreasing order based on the frequency of characters

转义

​ 将所给字符串按照其字符出现的频率从到到底排列,返回该结果。如果字符的频次相同顺序可以颠倒。

​ 如aaabbb 输出结果可以为bbbaaa 但是不能为ababab

整体求解思路

​ 1.利用map存储字符及该字符对应的频率。

2.利用选择排序将频率最大的字符,根据频率输出到结果字符串中。

3.输出结果之后将该字符的频率设置为0.

4.如果最后选择排序求出的最大频率为0则表示所有元素都被遍历到了,循环结束

代码
public class Solution {
    public String frequencySort(String s) {
        Map<Character,Integer> map=new HashMap<>();
        Set<Character> set=new HashSet<>();
        String result="";
        for(int i=0;i<s.length();i++)
        {
            char charAt = s.charAt(i);
            Integer integer = map.get(charAt);
            if(integer==null)
            {
                integer=1;
            }
            else
            {
                integer+=1;
            }
            map.put(charAt, integer);
        }
        for(Entry<Character,Integer> entry:map.entrySet())
        {
            int max=entry.getValue();
            char c=entry.getKey();
            for(Entry<Character,Integer>entry1:map.entrySet())
            {
                if(max<entry1.getValue())
                {
                    max=entry1.getValue();
                    c=entry1.getKey();
                }
            }
            if(max==0)
            {
                break;
            }
            map.put(c,0);
            for(int i=0;i<max;i++)
            {
                result+=c;
            }
        }
        return result;
    }
   
    @Test
    public void test1(){
        String s="";
        String frequencySort = frequencySort(s);
        System.out.println(frequencySort);
    }

遇到的问题:

​ 算法的运行时间超限。

分析以上算法的时间复杂度:

首先,利用了hashMap这种集合来进行字符以及它的频率的存储。由于hashMap底层的实现采用的是哈希表,所以对于hashMap的增加删除修改操作的平均时间复杂度均为O(1)。

1.遍历所有整个字符串,存储到hashMap中时间复杂度O(n)。

2.进行一个选择排序,时间复杂度O(n*n).

3.整体算法的时间复杂度为O(n*n).

该问题分类

​ 给定一个字符串->字符串按找规则重构->依照字符串中字符出现的频率从高到底重构该字符串

学习Discuss中的其他方案
思路

1.利用map存储字符串中的字符和该字符的对应关系。

2.创建一个list数组,数组的大小为整个字符串的长度+1,字符将按照其出现的频率存放到数组中(即该该字符的频率与他所在数组中的下标相同),

3.因为存放数组中的字符是按照其频率进行存储的,所以将数组倒序遍历即可得到结果字符串。

时间复杂度分析

1.采用HashMap存储整个字符串时间复杂度O(n).

2.将HashMap中的数据遍历到数组中时间复杂度O(n).

3.遍历数组将结果添加到结果集中,如果字符的平均频率为v的话,则时间复杂度为O(n*v)。

4.整体时间复杂度O(n*v). 这里v<=n.

代码
public class Solution {
    public String frequencySort(String s) {
        Map<Character, Integer> map = new HashMap<>();
        for (char c : s.toCharArray()) {
            if (map.containsKey(c)) {
                map.put(c, map.get(c) + 1);
            } else {
                map.put(c, 1);
            }
        }
        List<Character> [] bucket = new List[s.length() + 1];
        for (char key : map.keySet()) {
            int frequency = map.get(key);
            if (bucket[frequency] == null) {
                bucket[frequency] = new ArrayList<>();
            }
            bucket[frequency].add(key);
        }
        StringBuilder sb = new StringBuilder();
        for (int pos = bucket.length - 1; pos >=0; pos--) {
            if (bucket[pos] != null) {
                for (char num : bucket[pos]) {
                    for (int i = 0; i < map.get(num); i++) {
                        sb.append(num);
                    }
                }
            }
        }
        return sb.toString();
    }
}

5.205_Isomorphic_Strings

题目要求:

Given two strings s and t, determine if they are isomorphic.

Two strings are isomorphic if the characters in s can be replaced to get t.

All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.

Note:

You may assume both s and t have the same length.

转义:

判断两个字符串是否同构。

如:abc,cbd 同构

aab ccd 同构

aca eeg 不同构

遇到的问题:

这题的要求与前边的290题目要求差不多,所以我首先想到的是利用map的put方法去构建临时的对应关系,然后判断两个字符串这种关系是否相同。

但是每次放入到map中的元素都是一个字符,所以会出现A串中的字符与B串中的字符相同的情况,则该方法失效。

整体求解思路:

1.抽取模式,利用数字表示该模式,并存放到数组中。 2.对两个字符串分别抽取出该数组。如果两个数组相同则返回true,否则返回false

代码:
    public boolean isIsomorphic(String s, String t) {
        List<Integer> list=getPattern(s);
        List<Integer> list2=getPattern(t);
        for(int i=0;i<list.size();i++)
        {
            if(list.get(i)!=list2.get(i))
                return false;
        }
        return true;
    }
    private List<Integer> getPattern(String s) {
        Map<Character,Integer> map=new HashMap<>();
        List<Integer> list=new ArrayList<>();
        int k=1;//每个k对应一个字符 ,当字符相同的时候k的值不变
        for(int i=0;i<s.length();i++)
        {
            if(map.containsKey(s.charAt(i)))
            {
                list.add(map.get(s.charAt(i)));
            }
            else
            {
                map.put(s.charAt(i), k++);
                list.add(map.get(s.charAt(i)));
            }
        }
        return list;
    }
    @Test
    public void test1(){
        String s="aa";
        String t="ac";
        boolean isomorphic = isIsomorphic(s, t);
        System.out.println(isomorphic);
    }

该问题分类:

两个字符串->判断两个字符串是否符合某种关系->两个字符串是否保持相对位置和元素关系

学习Discuss中的其他方案
思路

1.利用map构建临时的对应关系。

2.比较两个字符串这种关系是否相同。

3.克服了字符相同这个问题:利用存储不同的数据类型,当存储A字符串中的字符用char类型,当存储B字符串中的字符用string类型。

代码
public class Solution {
    public boolean isIsomorphic(String s, String t) {
        Map m = new HashMap();
        for (Integer i=0; i<s.length(); ++i)
            if (m.put(s.charAt(i), i) != m.put(t.charAt(i)+"", i))
                return false;
        return true;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值