[高频] 三. 基础算法和数据结构I

641. Missing Intervals:  点击打开链接

思路:两端点和一头一尾形成的区间+for循环扫描中间形成的区间

例如:{3,4,50,75},lower=0,upper=99,题目可以理解成在0-99的区间,挖去了3,4,50,95四个点,求剩下的区间

区间:lower->3-1

         75+1->upper

         中间{3,4,50,75}的扫描

注意:Integer.MAX_VALUE+1=Integer.MIN_VALUE

         例如:输入[2147483647],0,2147483647,

         因为2147483647是Integer.MAX_VALUE,而2147483647+1=-2147483648,是Integer.MIN_VALUE

         因此会输出["0->2147483646","-2147483648->2147483647"]

         而期望输出["0->2147483646"]   

         所以三种情况每一种都要加上if判断       

public class Solution {
    /**
     * @param nums a sorted integer array
     * @param lower an integer
     * @param upper an integer
     * @return a list of its missing ranges
     */
    public List<String> findMissingRanges(int[] nums, int lower, int upper) {
        List<String> result = new ArrayList<String>();
        if(nums==null || nums.length==0){                                         //注意corner case
            getRange(result,lower,upper);
            return result;
        }
        
        if(nums[0]!=Integer.MIN_VALUE){
            getRange(result,lower,nums[0]-1);
        }
        
        for(int i=1;i<nums.length;i++){
            if(nums[i-1]!=Integer.MAX_VALUE && nums[i]!=Integer.MIN_VALUE){
                getRange(result,nums[i-1]+1,nums[i]-1);
            }
        }
        
        if(nums[nums.length-1]!=Integer.MAX_VALUE){
            getRange(result,nums[nums.length-1]+1,upper);
        }
        return result;
    }
    
    private void getRange(List<String> result,int start,int end){
        if(start>end){
            return;
        }else if(start==end){
            result.add(""+start);
            return;
        }else{
            result.add(""+start+"->"+end);
        }
    }
}

156. Merge Intervals: 点击打开链接

思路:区间start端点从小到大排序,从左到右扫一遍

         能合并,就合并

         不能合并,直接下一个

 

[                     [
  [1, 3],               [1, 6],
  [2, 6],      =>       [8, 10],
  [8, 10],              [15, 18]
  [15, 18]            ]
]

分析:开始last=null,i=[1,3],res加入[1,3],并且last=[1,3];

 

         i=[2,6],和last=[1,3]可以合并,更新res里[1,3]的end值使称为[1,6];

         i=[8,10],res加入[8,10],并且last=[8,10];

注意:时间复杂度O(nlogn)

          扫描一次n,排序nlogn

 

/**
 * Definition of Interval:
 * public class Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this.start = start;
 *         this.end = end;
 *     }
 */

class Solution {
    /**
     * @param intervals, a collection of intervals
     * @return: A new sorted interval list.
     */
    public List<Interval> merge(List<Interval> intervals) {
        ArrayList<Interval> res = new ArrayList<>();  
        
        Collections.sort(intervals,myComparator);
        Interval last=null;
        for(Interval i:intervals) {  
            if(last==null || last.end<i.start){  
                res.add(i);  
                last=i;
            } else{
                last.end = Math.max(last.end, i.end);                         //更新已经在result list里的元素的end       
            }
        }  
        return res;
    }
    private Comparator<Interval> myComparator = new Comparator<Interval>() {  
        public int compare(Interval i, Interval j) {  
            return i.start - j.start;  
        }  
    };
}
 public int[][] merge(int[][] intervals) {
        if(intervals == null || intervals.length <2)
        {
            return intervals;
        }
        
        Arrays.sort(intervals, (a,b) -> Integer.compare(a[0], b[0]));
        
        
        List<int[]>  list = new ArrayList<>();          
        for(int i=0; i<intervals.length; i++)
        {
            int left = intervals[i][0];
            int right = intervals[i][1];
            
            while(i+1<intervals.length && right >= intervals[i+1][0])
            {
                right = Math.max(right, intervals[i+1][1]);
                i++;
            }
            list.add(new int[]{left, right});
        }
                    
         return list.toArray(new int[list.size()][]);
    }

30.  Insert Intervals: 点击打开链接

Insert [2, 5] into [[1,2], [5,9]], we get [[1,9]].

 

Insert [3, 4] into [[1,2], [5,9]], we get [[1,2], [3,4], [5,9]]

/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
public class Solution {
    public List<Interval> insert(List<Interval> intervals, Interval newInterval) {      //方法一
        List<Interval> result=new ArrayList<>();
        int index=0;
        while(index<intervals.size() && intervals.get(index).start<newInterval.start){  //先插入到正确位置
            index++;                                                                    //使整个给定list还是按start升序
        }
        intervals.add(index,newInterval);
        
        Interval last=null;                                                             //然后是merge Intervals
        for(Interval i:intervals){
            if(last==null || last.end<i.start){
                result.add(i);
                last=i;
            }else if(last.end>=i.start){
                last.end=Math.max(i.end,last.end);
            }
        }
        return result;  
    }
}

 

/**
 * Definition of Interval:
 * public classs Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this.start = start;
 *         this.end = end;
 *     }
 */

class Solution {
    /**
     * Insert newInterval into intervals.
     * @param intervals: Sorted interval list.
     * @param newInterval: A new interval.
     * @return: A new sorted interval list.
     */
    public ArrayList<Interval> insert(ArrayList<Interval> intervals, Interval newInterval) {    //方法二
        ArrayList<Interval> result = new ArrayList<Interval>();
             
        for(Interval i: intervals){
            if(i.end < newInterval.start){                              //insert[3,4]与[1,2]比较
                result.add(i);
            }else if(i.start > newInterval.end){                        //insert[3,4]与[5,9]比较 
                result.add(newInterval);
                newInterval = i;        
            }else{                                                      //其他情况就是start取小,end取大
                int newStart = Math.min(i.start, newInterval.start);
                int newEnd = Math.max(newInterval.end, i.end);
                newInterval = new Interval(newStart, newEnd);           //并且不断更新newInterval
            }
         }
         result.add(newInterval); 
         return result;
    }
}

646. First Position Unique Character:点击打开链接

public class Solution {
    /**
     * @param s a string
     * @return it's index
     */
    public int firstUniqChar(String s) {
        if(s==null || s.length()==0){
            return -1;
        }
        
        Map<Character,Integer> map=new HashMap<>();
        for(int i=0;i<s.length();i++){
            char ch=s.charAt(i);
            if(!map.containsKey(ch)){
                map.put(ch,1);
            }else{
                map.put(ch,map.get(ch)+1);
            }
        }
        
        for(int i=0;i<s.length();i++){                       //这里可以直接返回i
            if(map.get(s.charAt(i))==1){
                return i;
            }
        }
        return -1;
    }
}

423. Valid Parentheses:点击打开链接

思路:如果"([{}])",遇到前三个,stack里装了)]},当到了},stack该push},一样就继续遍历,不一样就返回false

public class Solution {
    /**
     * @param s A string
     * @return whether the string is a valid parentheses
     */
    public boolean isValidParentheses(String s) {
        if(s==null || s.length()==0){
            return false;
        }
        Stack<Character> stack=new Stack<>();
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(c=='('){
                stack.push(')');
            }else if(c=='{'){
                stack.push('}');
            }else if(c=='['){
                stack.push(']');
            }else if(stack.isEmpty()||stack.pop()!=c){     //如果"()]",当遇到]stack该执行pop,但没有东西在stack里    
                return false;                              //还有就是如果pop出的不一样,也返回false
            }
        }
        return stack.isEmpty();                            //如果")()",如果一开始就该pop,stack此时为空,还是要返回false
    }
}

647. Substring Anagrams:点击打开链接

思路:统计好p字符串每个字符出现的次数

         sliding window从左往右扫一遍,每次判断p.length区间段的字符是不是能还原成p字符串

        都是减少一个左边元素,同时增加一个右边元素,

public class Solution {
    /**
     * @param s a string
     * @param p a non-empty string
     * @return a list of index
     */
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> result=new ArrayList<>();
        int[] temp=new int[26];
        for(Character i:p.toCharArray()){
            temp[i-'a']++;
        }
        
        int start=0,end=0;
        int matched=0;
        while(end<s.length()){
            if(temp[s.charAt(end)-'a'] >=1){            //开始已经统计过p字符串,因此只要分p里有的,这里的个数至少为1
                matched++;                              //每一个符合条件的都matched++
            }
            temp[s.charAt(end)-'a']--;                  //已经统计到matched上的,就要从自身字符的总个数上减掉
            end++;                                      //或者是不matched的,也要从自身字符的总个数上减掉,会成为-1或更小负数
            
            if(matched==p.length()){                    //没达到p.length不会添加
                result.add(start);
            }
            
            if(end-start==p.length()){                  //一开始从索引0往后遍历end,没达到p.length(),这里不执行
                if(temp[s.charAt(start)-'a'] >=0){      //当达到p.length()才进行sliding window
                    matched--;                          //如果遍历到的字符自身总个数>=0,说明一开始end遍历的时候属于p里的字符
                }                                       //减少一个左边的字符
                temp[s.charAt(start)-'a']++;            //但是要补回来左边减少的字符,以便接下来end判断右面是不是有这个字符
                start++;                                //如果左边这个字符不是p里有的,也要统计上,因为之前end遍历的时候已经成负数
            }                                           //因此怎么加也不是在下一次end判断的时候自身字符总数>=1
        }
        return result; 
    }
}

648. Word Abbreviation Set: 点击打开链接

方法一

思路:单词在字典中出现次数等于对应缩写在字典中的次数,unique

         单词在字典中出现次数等于对应缩写在字典中的次数,not unique

public class ValidWordAbbr {
    // @param dictionary a list of word
    Map<String,Integer> mapA=new HashMap<>();
    Map<String,Integer> mapW=new HashMap<>();
    public ValidWordAbbr(String[] dictionary) {
        for(String word:dictionary){
            String abbr=getAbbr(word);
            if(!mapA.containsKey(abbr)){
                mapA.put(abbr,1);
            }else{
                mapA.put(abbr,mapA.get(abbr)+1);
            }
        }
        for(String word:dictionary){
            if(!mapW.containsKey(word)){
                mapW.put(word,1);
            }else{
                mapW.put(word,mapW.get(word)+1);
            }
        }
    }

    /**
     * @param word a string
     * @return true if its abbreviation is unique or false
     */
    public boolean isUnique(String word) {
        return mapA.get(getAbbr(word))==mapW.get(word);
    }
    
    private String getAbbr(String word){
        if(word.length()<=2){
            return word;
        }
        return ""+word.charAt(0)+String.valueOf(word.length()-2)+word.charAt(word.length()-1);
    }
}
/**
 * Your ValidWordAbbr object will be instantiated and called as such:
 * ValidWordAbbr obj = new ValidWordAbbr(dictionary);
 * boolean param = obj.isUnique(word);
 */

方法二

思路:Map<缩写词,第一个遍历的单词>,当map里已经有这个缩写词,就要看下对应值的是不是同一个单词,如果不是,说明不是唯一

注意:在判断是不是唯一的时候,如果新的单词不是字典里已经有的,说明也是唯一

public class ValidWordAbbr {
    // @param dictionary a list of word
    Map<String,String> map;
    public ValidWordAbbr(String[] dictionary) {
        map=new HashMap<>();
        for(String word:dictionary){
            String abbr=getAbbr(word);
            if(!map.containsKey(abbr)){
                map.put(abbr,word);
            }else{                                                //如果map里有key有abbr
                if(!map.get(abbr).equals(word)){                  //判断key对应的值映射不是当前word,而是之前已经有的word
                    map.put(abbr,"-1");                           //说明不是唯一,用"-1"来记
                }
            }
        }
    }

    /**
     * @param word a string
     * @return true if its abbreviation is unique or false
     */
    public boolean isUnique(String word) {
        String abbr=getAbbr(word);                                //返回true的两种情况
        if(!map.containsKey(abbr)){                               //给出word的abbr不在字典里
            return true;
        }
        return map.get(abbr).equals(word)?true:false;             //map的值映射是word,因为如果不是唯一值映射就是"-1"
    }
    
    private String getAbbr(String word){
        if(word.length()<=2){
            return word;
        }
        return ""+word.charAt(0)+String.valueOf(word.length()-2)+word.charAt(word.length()-1);
    }
}
/**
 * Your ValidWordAbbr object will be instantiated and called as such:
 * ValidWordAbbr obj = new ValidWordAbbr(dictionary);
 * boolean param = obj.isUnique(word);
 */

124. Longest Consecutive Sequence: 点击打开链接

例如:{100,4,200,1,3,2},对于数组里的每一个元素e,都看e-1和e+1是否在set里,如果在,就一直往下找,最后算出长度

         为了能直接在set里判断,一开始就要把数组里所有元素放在set里

注意:因为只需要扫面一遍数组里的元素,因此O(n)

public class Solution {
    /**
     * @param nums: A list of integers
     * @return an integer
     */
    public int longestConsecutive(int[] num) {
        if(num == null || num.length == 0){
            return 0;
        }
        
        Set<Integer> set=new HashSet<>();
        for(Integer e:num){
            set.add(e);
        }
        
        int result=0;
        for(Integer e:num){
            int pre=e-1;
            int next=e+1;
            while(set.contains(pre)){
                set.remove(pre);
                pre--;
            }
            while(set.contains(next)){
                set.remove(next);
                next++;
            }
            result=Math.max(result,next-pre-1);
        }
        
        return result;
    }
}

526. Load Balancer:点击打开链接

思路:O(1)时间内插入,删除,只能hash

         但是还要getRandom(),就要数组或者list来做

public class LoadBalancer {
    
    // This is consistent hashing solution in most companies. However it exceeds the memory limit
    List<Integer> list;
    Map<Integer,Integer> map;
    
    public LoadBalancer() {
        list=new ArrayList<>();
        map=new HashMap<>();
    }

    // @param server_id add a new server to the cluster 
    // @return void
    public void add(int server_id) {
        list.add(server_id);                                            //list加入这个元素,其实每次加入的元素都是在list末尾
        map.put(server_id,list.size()-1);                               //map里放要添加的server_id和它在list里的位置
    }

    // @param server_id server_id remove a bad server from the cluster
    // @return void
    public void remove(int server_id) {
        if(map.containsKey(server_id)){      
            int index=map.get(server_id);                               //拿到要删除的server_id在map里的位置
            list.set(index,list.get(list.size()-1));                    //list把该位置更新成最后一个元素
            map.put(list.get(list.size()-1),index);                     //map里也把该位置更新成list的最后一个元素
            
            list.remove(list.size()-1);                                 //删除list最后一个元素
            map.remove(server_id);                                      //map删除要删除的server_id
        }
    }

    // @return pick a server in the cluster randomly with equal probability
    public int pick() {
        Random r = new Random();
        return list.get(r.nextInt(list.size()));                        //r.nextInt(n):表示从0到n(不包括n)随机取数       
    } 
}

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值