▊【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