[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;
    }
}

     
          
       
           

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值