【LeetCode】Sama的个人记录_3

 

 

▊【Q12】(md) 整数转罗马数字
 
  罗马数字包含以下七种字符: I, V, X, L,C,D ,M。
 
  字符-数值 I-1, V-5, X -10, L- 50,C-100, D-500, M-1000
 
  通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
 
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
 
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
 
示例 1:

   输入: 3
   输出: “III”
示例 2:

   输入: 4
   输出: “IV”
示例 3:

   输入: 9
   输出: “IX”
示例 4:

   输入: 58
   输出: “LVIII”
   解释: L = 50, V = 5, III = 3.
示例 5:

   输入: 1994
   输出: “MCMXCIV”
   解释: M = 1000, CM = 900, XC = 90, IV = 4.

class Solution {
    public String intToRoman(int num) {
    	/*
    	* 【取余法】
    	* 思路 : 每次除法,商是这个被除数对应的罗马数字的个数,接着对余数进行同样的除法操作
    	* 其本质是 :将这个整数,分成了以罗马数字单位(1000,900...5,4,1)的组合 ★
    	*/
    	int[] n = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    	String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
    	StringBuffer s = new StringBuffer();
    	for(int i = 0 ; i < n.length ; i++) {
    		int t = num / n[i];
    		while(t > 0) {
    			s.append(roman[i]);
    			t--;
    		}
    		num = num % n[i];
    	}
    	return s.toString();
    }
}

 

class Solution {
    public String intToRoman(int num) {
    	/*
    	* 【贪心算法】
    	* 思路和"尽可能用最大面值的纸币的组合表示一个金额"的问题一样,都是寻找"此时还可以用的最大面额"
    	* 这种在每一步中寻求最优解而不用考虑整体的思想,是典型的贪心
    	*/
    	int[] n = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    	String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
    	StringBuffer s = new StringBuffer();
    	int index = 0;
    	while(index < n.length) {
    		while(num >= n[index]) {
    			s.append(roman[index]);
    			num -= n[index];
    		}
    		index++;
    	}
    	return s.toString();
    }
}

 

 

▊【Q13】(md) 罗马数字转整数
 
  题目不再赘述,是上题的逆运算

class Solution {
	/*
	* 思路:从罗马数字字符串的开头,一步步切割出数字(也算是贪心)
	* 其实这种算法的安全性来源于罗马数字本身的巧妙规则:
	* M,CM,C分别对应1000,900,100,因此我们安全分割下了M;试想,如果像C,CM,M这样对应,还能安全分割下C吗?
	*/
    public int romanToInt(String s) {
    	int[] n = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    	String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
    	int index = 0;
    	int num = 0;
    	while(s.length() > 0) {
    		while(s.startsWith(roman[index])) {				//startWith的使用省去了对长度的if-else
    			num += n[index];
    			s = s.substring(roman[index].length());
    		}
    		index ++;
    	}
    	return num;
    }
}

 

 

▊【Q15】(md) 三数之和问题
 
  给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a+ b + c = 0 ?请你找出所有满足条件且不重复的三元组。
 
注意:答案中不可以包含重复的三元组。
 
示例:
 
  给定数组 nums = [-1, 0, 1, 2, -1, -4],
 
  满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

>>> 暴力法就不贴了;以后遇到这样的问题必须强迫自己直接扼杀掉暴力法的思路
>>> 这是一个典型的双指针的问题
>>> 这个算法很重要很重要很重要很重要
class Solution {
    public static List<List<Integer>> threeSum(int[] nums) {
    	/*
    	* 【双指针算法】
    	* 思路 :
    	* 1.先排序(很重要,想不到就麻烦了)
    	* 2.固定第一项(i),然后对右面的部分取最左侧指针(L)和最右侧指针(R)
    	* 3.i+L+R(伪代码,指内容相加) :
    	* 	和 < 0,说明负数绝对值太大,左指针L右移
    	*   和 > 0,说明正数绝对值太大,右指针R左移
    	*   和 = 0,L右移同时R左移
		* 
		* 明确下面几点:
		* ★ for i 语句是完成这个三项双指针结构的关键
		* ★ L,R不再移动(即此刻i对应的情况已经完全讨论结束)的条件时while(L < R)
		* ★ 这个问题的另个难点,关键,和巧妙之处在于“查重”操作
    	*/
    	int len = nums.length;
    	List<List<Integer>> list = new ArrayList<>();
    	
    	if(len < 3)	 return list; 
    	Arrays.sort(nums);
    	for(int i = 0 ; i < len - 2 ; i++) {
    		if(nums[i] > 0)  break;				//如果当前的i对应的数字已经大于了0, 那么三数之和必不可能为零
    		if(i > 0 && nums[i] == nums[i-1])	continue;					//去重(注意写continue)
    		int L = i + 1;
    		int R = len - 1;
    		while(L < R) {
    			int sum = nums[i] + nums[L] + nums[R];
    			if(sum == 0) {
    				list.add(Arrays.asList(nums[i], nums[L], nums[R]));
    				while(L < R && nums[L] == nums[L + 1])  L++;			//去重(注意写上L < R)
    				while(L < R && nums[R] == nums[R - 1])  R--;			//去重(注意写上L < R)
    				L++;
    				R--;
    			}else if(sum < 0) {
    				L++;
    			}else if(sum > 0) {
    				R--;
    			}
    		}
    	}
    	return list;
    }
}

 

 

▊【Q16】(md) 最接近的三数之和
 
  给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
 
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
 
与 target 最接近的三个数的和为 2 (-1 + 2 + 1 = 2)

class Solution {
    public int threeSumClosest(int[] nums, int target) {
    	/*
    	* 【双指针算法】
    	* 与上题相似,同样是i,L,R三项双指针结构
    	* 不同之处在于:多了一个差值dev判断(最小时对应的sum的是最终结果res);少了去重操作
    	*/
    	Arrays.sort(nums);
    	int len = nums.length;
    	int res = 0;
    	int min = Integer.MAX_VALUE;
    	
    	for(int i = 0 ; i < len ; i++) {
    		if(i > 0 && nums[i] == nums[i - 1])	continue;		// 简单去重,稍微优化一点点算法
    		int L = i + 1;
    		int R = len - 1;
    		while(L < R) {
    			int sum = nums[i] + nums[L] + nums[R];
    			int dev = sum > target ? sum - target : target - sum;
    			if(sum == target) {
    				return target;
    			}else if(sum < target) {
    				if(dev < min) {
    					min = dev;
    					res = sum;
    				}
    				L++;
    			}else if(sum > target) {
    				if(dev < min) {
    					min = dev;
    					res = sum;
    				}
    				R--;
    			}
    		}
    	}
    	return res;
    }
}

 

 

 

 

 

 

 

 

 

 

Qs from https://leetcode-cn.com
♠ loli suki
♦ end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值