leetcode 670. Maximum Swap

257 篇文章 17 订阅

Given a non-negative integer, you could swap two digits at most once to get the maximum valued number. Return the maximum valued number you could get.

Example 1:

Input: 2736
Output: 7236
Explanation: Swap the number 2 and the number 7.

Example 2:

Input: 9973
Output: 9973
Explanation: No swap.

Note:

  1. The given number is in the range [0, 108]
这道题需要注意如下的测试用例。


我使用helper也是为了对付这种情形。如果最大数出现在开头的话,比如98368,那么需要继续递归问题给8368。

public int maximumSwap(int num) {
	ArrayList<Integer> digitsTmp=new ArrayList<Integer>();
	int tmpNum=num;
	while(tmpNum>=1){
		digitsTmp.add(tmpNum%10);
		tmpNum=tmpNum/10;
	}
	int n=digitsTmp.size();
	int[] digits=new int[n];
	for(int i=n-1;i>=0;i--){
		digits[n-1-i]=digitsTmp.get(i);
	}//到这里是将num拆分为一个个数字放入digits数组中
	helper(digits,0,n);
	int result=0;
	for(int i=0;i<n;i++){
		result=result*10;
		result+=digits[i];
	}
	return result;
}

public void helper(int[] digits,int beginIndex,int n){
	if(beginIndex==n){
		return;
	}
	int maxDigit=digits[beginIndex];
	int max_index=beginIndex;
	for(int i=beginIndex;i<n;i++){
		if(digits[i]>=maxDigit){
			maxDigit=digits[i];
			max_index=i;
		}
	}
	if(maxDigit==digits[beginIndex]){
		helper(digits, beginIndex+1, n);
	}
	else{
		int tmp=digits[beginIndex];
		digits[beginIndex]=maxDigit;
		digits[max_index]=tmp;
		return;
	}
}
大神则想出了O(n)时间复杂度的方法:

使用 buckets 来记录数字 0 ~ 9 的最后出现位置。

从左到右遍历num的数字,对于每个位置,我们查找是否在之后的位置中存在一个比它更大的数(从 9 一直找到当前位置的数字大小)。我们也需要确保 这个更大的数字的位置 是 位于当前位置 之后的。如果找到了,我们就可以交换这两个数字的位置,返回结果。

class Solution {
    public int maximumSwap(int num) {
        char[] digits = Integer.toString(num).toCharArray();
        
        int[] buckets = new int[10];
        for (int i = 0; i < digits.length; i++) {
            buckets[digits[i] - '0'] = i;
        }
        
        for (int i = 0; i < digits.length; i++) {      //从最高位开始
            for (int k = 9; k > digits[i] - '0'; k--) {    // k需要比数字digits[i]大
                if (buckets[k] > i) {     //如果k的位置在i后面
                    char tmp = digits[i];
                    digits[i] = digits[buckets[k]];
                    digits[buckets[k]] = tmp;
                    return Integer.valueOf(new String(digits));
                }
            }
        }
        
        return num;
    }
}
还有大神用了另一种 O(n) 的方法。

这个方法的思路在于:如果有一个低位数字比高位数字要大,那么交换它们肯定能使得当前数变得更大。为了在交换后得到最大的数,不但需要:与可能的最高位交换,也需要:确保你交换到最高位的数要尽量足够大。

算法如下:

  1. 从最低位一直遍历到最高位,存储迄今为止最大的数字。

  2. 如果当前数字比迄今为止最大的数字小,那么存储swap索引:当前数字的索引 和 迄今为止最大数字的索引。
    如果当前数字比迄今为止最大的数字大,那么重置 迄今为止最大的数字。

  3. 最后,交换之前存储的两个swap索引。重新计算数字。

maxSeen :迄今为止最大的数字。
maxIdx :迄今为止最大数字的索引。
power :当前访问数字的索引
swapIdx's :需要被交换的数字 的索引

class Solution {
    public int maximumSwap(int num) {
        int maxSeen = 0, maxIdx = -1, power = 0, swapIdx1 = 0, swapIdx2 = 0;
        List<Integer> list = new ArrayList<>();
        while(num > 0){
            int digit = num % 10;
            list.add(digit);
            if(maxSeen > digit){
                swapIdx1 = power;
                swapIdx2 = maxIdx;
            }
            else if(digit > maxSeen){
                maxSeen = digit;
                maxIdx = power;
            }
            num = num/10;
            power++;
        }
        
        Collections.swap(list, swapIdx1, swapIdx2);

        int result = 0;
        for(int i = 0; i < list.size(); i++){
            result += (int)(Math.pow(10, i) * list.get(i));
        }
        return result;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值