[US Giants] 五. Greedy

Single Number

Given 2*n + 1 numbers, every numbers occurs twice except one, find it.

Example: Given [1,2,2,1,3,4,3], return 4
Challenge One-pass, constant extra space.
思路:HashMap用了extra O(n) space,不符合題目要求的O(1) extra space

public class Solution {
    /**
      *@param A : an integer array
      *return : a integer 
      */
    public int singleNumber(int[] A) {                           //不符合題目要求空間複雜度
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<A.length;i++){
            if(!map.containsKey(A[i])){
                map.put(A[i],1);
            }else{
                map.put(A[i],map.get(A[i])+1);
            }
        }
        
        int result=0;
        for(Integer i:map.keySet()){
            if(map.get(i)==1){
                result=i;
            }
        }
        return result;
    }
}
思路:異或運算
           任意兩個相同的數做異或運算結果爲0
           也就是,數a兩次異或同一個數b,仍然爲數a,例如a^b^b=a,並且異或有交換律
public class Solution {
    /**
      *@param A : an integer array
      *return : a integer 
      */
    public int singleNumber(int[] A) {
        if(A==null || A.length==0){
            return 0;
        }
        int result=0;
        for(int i=0;i<A.length;i++){
            result^=A[i];
        }
        return result;
    }
}

Single Number II

Given 3*n + 1 numbers, every numbers occurs triple times except one, find it.

Example:Given [1,1,2,3,3,3,2,2,4,1] return 4
Challenge:  One-pass, constant extra space.

思路:利用位運算來消除重複三次的數

1110
1110
1110
1001
4331    對每一位進行求和
1001    對每一位的和做%3運算,來消除所有重複3次的數

public class Solution {
	/**
	 * @param A : An integer array
	 * @return : An integer 
	 */
    public int singleNumberII(int[] A) {
        int[] bits=new int[32];
        for(int i=0;i<A.length;i++){
            for(int j=0;j<32;j++){
                int move;
                if((move=A[i]>>j)==0){            //右移:二進制表示除以2 
                    break;
                }
                bits[j]+=move & 1;                //按位與:只有兩位同時爲1,結果才爲1
            }
        }
        
        int target=0;
        for(int i=0; i<32; i++){
            target+=(bits[i]%3 <<i);
        }
        return target;
    }
}

Majority Number

Given an array of integers, the majority number is the number that occurs more than half of the size of the array. Find it.

You may assume that the array is non-empty and the majority number always exist in the array.

Example:Given [1, 1, 1, 1, 2, 2, 2], return 1
Challenge O(n) time and O(1) extra space
思路:先初始化出現次數大於一半的數major爲list的第一個數,並且初始化major的個數count=1

         從i=1,第二個數開始遍歷list,

         如果遍歷到的數等於major,count++

         如果遍歷到的數不等於major,如果此時的count>0,還有可以抵消的數,就count--,否則就重置major

想法:因爲major出現的次數多餘一半,因此當真正的major被置爲major的時候,它的個數一定可以被所有其他的數用來抵消,最後還有剩餘,返回即可

public class Solution {
    /**
     * @param nums: a list of integers
     * @return: find a  majority number
     */
    public int majorityNumber(ArrayList<Integer> nums) {
        int major=nums.get(0);
        int count=1;
        for(int i=1;i<nums.size();i++){
            if(nums.get(i)==major){
                count++;
            }else{
                if(count>0){
                   count--; 
                }else{
                    major=nums.get(i);
                }
            }
        }
        return major;
    }
}

Majority Number II

Given an array of integers, the majority number is the number that occurs more than 1/3 of the size of the array.

Find it.

There is only one majority number in the array.

Example : Given [1, 2, 1, 2, 1, 3, 3], return 1.
Challenge O(n) time and O(1) extra space.
思路:從頭開始遍歷,如果有三個不一樣的數,就抵消掉,記錄兩個candidate和每個candidate出現的次數count。
         如果遍歷到的數和兩個candidate都不等,兩個count都減1,表示出現了三個不一樣的數,要抵消掉。
         最後再重新遍歷一次list,找到主元素。
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: The majority number that occurs more than 1/3
     */
    public int majorityNumber(ArrayList<Integer> nums) {
        if(nums==null || nums.size()==0){
            return -1;
        }
        
        int candidate1=0;
        int candidate2=0;
        int count1=0;
        int count2=0;
        for(int i=0;i<nums.size();i++){
            if(nums.get(i)==candidate1){
                count1++;
            }else if(nums.get(i)==candidate2){
                count2++;
            }else if(count1==0){
                candidate1=nums.get(i);
                count1=1;
            }else if(count2==0){
                candidate2=nums.get(i);
                count2=1;
            }else{
                count1--;
                count2--;
            }
        }
        
        count1=count2=0;
        for(int i=0;i<nums.size();i++){
            if(nums.get(i)==candidate1){
                count1++;
            }else if(nums.get(i)==candidate2){
                count2++;
            }
        }
        return count1>count2?candidate1:candidate2;
    }
}

Gas Station

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station's index if you can travel around the circuit once, otherwise return -1.

The solution is guaranteed to be unique.

Example

Given 4 gas stations with gas[i]=[1,1,3,1], and the cost[i]=[2,2,1,1]. The starting gas station's index is 2.

Challenge :  O(n) time and O(1) extra space

思路:從頭開始遍歷,(每個加油站能加到的油) - (這個加油站到下一個加油站消耗的油),就是當前剩餘記爲temp

          如果當前剩餘temp<0,說明不能從這個站開始走,要嘗試從下一個站開始走,此時temp又要重置爲0

          如果可以走,一直遍歷到最後

          如果(總加到的油量) - (總消耗的油量),也就是sum<0,說明走不到底,返回-1,否則就返回嘗試開始走的index

public class Solution {
    /**
     * @param gas: an array of integers
     * @param cost: an array of integers
     * @return: an integer
     */
    public int canCompleteCircuit(int[] gas, int[] cost) {
        if(gas==null || cost==null || gas.length==0 || cost.length==0){
            return -1;
        }
        
        int temp=0;
        int sum=0;
        int index=0;
        for(int i=0;i<gas.length;i++){
            temp+=gas[i]-cost[i];
            sum+=gas[i]-cost[i];                       //從開始遍歷的時候就計數
            if(temp<0){
               index=i+1;
               temp=0;
            }
        }
        return sum<0?-1:index;
    }
}

Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.

The result may be very large, so you need to return a string instead of an integer.

Example

Given [1, 20, 23, 4, 8], the largest formed number is 8423201.

Challenge Do it in O(nlogn) time complexity.

思路:先將整形數組轉換爲字符串數組

          然後調用myComparator比較器使字符串按照相加結果的從大到小排序,例如[34,30,9]->[9,34,30]

          再依次取出每一個字符串數組的元素拼接好即可。

          但是要注意一些情況,比如[0,0],輸出要是"0",而不是"00",因此,只要排序好的數組的第一個元素的第一位是'0',結果就是一定是”0“

public class Solution {
    /**
     *@param num: A list of non negative integers
     *@return: A string
     */
    public String largestNumber(int[] num) {
        if(num==null || num.length==0){
            return "";
        }
        
        String[] temp=new String[num.length];
        for(int i=0;i<num.length;i++){
            temp[i]=String.valueOf(num[i]);
        }
        
        Arrays.sort(temp,myComparator);
        String result="";
        if(temp[0].charAt(0)=='0'){
            return "0";
        }
        for(int i=0;i<temp.length;i++){
            result+=temp[i];
        }
        return new StringBuffer(result).toString();
    }
    
    private Comparator<String> myComparator=new Comparator<String>(){        //我這裏按從大到小排序,也可以從小到大
        public int compare(String a,String b){
            return (b+a).compareTo(a+b);
        }
    };
}

Next Permutation

Given a list of integers, which denote a permutation.

Find the next permutation in ascending order.

The list may contains duplicate integers.

Example

For [1,3,2,3], the next permutation is [1,3,3,2]

For [4,3,2,1], the next permutation is [1,2,3,4]

思路:儘可能地不去增加高位,因爲增加高位數字會變更大,比如124751這個序列,增加第n位的前提是前n-1位已經達到了最大
         從後向前看:1,51,751,已經是各自的最大情況,當到4751的時候,就要把4移動到後面來使數字整體增大
         4要移動到的位置,就是4後面的比4大卻是儘可能小的數,從右向左遍歷4後面的數字,第一個比4大的就是符合條件的,找到5,
         4和5交換位置,交換後成了5741,741是個降序排列,再把741->147升序即可。
public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A list of integers that's next permuation
     */
    public int[] nextPermutation(int[] nums) {
        if(nums.length <= 1){
            return nums;
        }
        int i=nums.length-2;
        
        while(i>=0 && nums[i]>=nums[i+1]){               //找到第一個下降點,還要注意等於的情況也要跳過
            i--;
        }
        if(i>=0){                                        //從右向左找到第一個比下降點大,卻儘可能小的數
            int j=nums.length-1;
            while(j>i && nums[j]<=nums[i]){
                j--;
            }
            swap(nums, i, j);                            //交換兩個數
        }
        reverse(nums, i+1, nums.length-1);               //下降點後面遍歷過的序列reverse成升序列
        return nums;                                     //如果本來就是最大序列,像4321,while循環的時候i會i減小到-1
    }                                                    //然後就是整個序列reverse
    
    private void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
    
    private void reverse(int[] nums,int left,int right){
        while(left<right){
            swap(nums,left++,right--);
        }
    }
}

Delete Digits

Given string A representative a positive integer which has N digits, remove any k digits of the number, the remaining digits are arranged according to the original order to become a new positive integer.

Find the smallest integer after remove k digits.

N <= 240 and k <= N

Example

Given an integer A = "178542", k = 4

return a string "12"

思路:對於k次循環,每次刪掉一個最前面的高峯點
public class Solution {
    /**
     *@param A: A positive integer which has N digits, A is a string.
     *@param k: Remove k digits.
     *@return: A string
     */
    public String DeleteDigits(String A, int k) {
        StringBuffer sb = new StringBuffer(A);
        int i,j;
        for (i=0;i<k;i++) {
            for (j=0; j<sb.length()-1 && sb.charAt(j)<=sb.charAt(j+1); j++) {}
            sb.delete(j, j+1);
        }
        while (sb.length()>1 && sb.charAt(0)=='0') {                               //刪完如果有前導零,去掉
            sb.delete(0, 1);
        }
        return sb.toString();
    }
}

jump Games

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Determine if you are able to reach the last index.

This problem have two method which is Greedy and Dynamic Programming.

The time complexity of Greedy method is O(n).

The time complexity of Dynamic Programming method is O(n^2).

We manually set the small data set to allow you pass the test in both ways. This is just to let you learn how to use this problem in dynamic programming ways. If you finish it in dynamic programming ways, you can try greedy method to make it accept again.

Example

A = [2,3,1,1,4], return true.

A = [3,2,1,0,4], return false.

思路:先初始化可以reach的地方是A[0],從i=1開始遍歷,在reach包含的每個點地方起步
         判斷該點的reach是否大於等於當前reach,如果是,更新reach,說明又能reach的距離更長了
         直到可以reach到最後
public class Solution {
    /**
     * @param A: A list of integers
     * @return: The boolean answer
     */
    public boolean canJump(int[] A) {
       int reach=A[0];
       for(int i=1;i<A.length;i++){
           if(reach>=i && A[i]+i>=reach){
               reach=A[i]+i;
           }
       }
       return reach>=A.length-1;
    }
}

     
          
       
           

發佈了102 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章