归纳0-错题本-操作技巧
1-排序的用法
- 实现数据的顺序排列;
- 在数据有重复时,实现相同数据的聚集(能这样做的前提是,最终结果与原先的顺序无关)。
2-数字字典序
- 如果是正常字符串字典序,那么java中
a.compareTo(b)
就是排序结果,返回负值表示a在b前,返回正值表示a在b后 - https://leetcode-cn.com/problems/lexicographical-numbers/
import java.util.ArrayList;
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> lexicalOrder(int n) {
int ans = 1;
for(int i=0; i<n; i++){
res.add(ans);
if(ans * 10 <= n){
ans *= 10;
}else{
while(ans%10==9 || ans+1>n){
ans /= 10;
}
ans++;
}
}
return res;
}
}
2-1-字典序,逻辑并不像自己想的那么好写
import java.util.HashMap;
class Solution {
public boolean isAlienSorted(String[] words, String order) {
HashMap<Character, Integer> cache = new HashMap<>();
for(int i=0; i<order.length(); i++){
cache.put(order.charAt(i), i);
}
for(int i=0; i<words.length-1; i++){
String word1 = words[i];
String word2 = words[i+1];
int length = Math.min(word1.length(), word2.length());
flag:{
for(int j=0; j<length; j++){
if(word1.charAt(j)==word2.charAt(j)){
continue;
}else if(cache.get(word1.charAt(j))>cache.get(word2.charAt(j))){
return false;
}else{
break flag;
}
}
if(word1.length()>word2.length()){
return false;
}
}
}
return true;
}
}
3-java借助StringBuilder进行快速序列化(int和char之间的转换)
//序列化
public String serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
postOrder(root, sb);
//System.out.println(sb.toString());
return sb.toString();
}
void postOrder(TreeNode root, StringBuilder sb){
if(root==null){
return;
}
postOrder(root.left, sb);
postOrder(root.right, sb);
sb.append((char)root.val); //利用java自带的字符集,进行int->char->string的快速转换
}
//反序列化
public TreeNode deserialize(String data) {
//System.out.println(dataArray[0]);
LinkedList<Integer> dataList = new LinkedList<>();
for(int i=0; i<data.length(); i++){
dataList.add((int)data.charAt(i)); //利用java自带的字符集,进行string->char->int的快速转换
}
//System.out.println(dataList.toString());
return dePostOrder(Integer.MIN_VALUE, Integer.MAX_VALUE, dataList);
}
TreeNode dePostOrder(int minValue, int maxValue, LinkedList<Integer> dataList){
//System.out.println(dataList.peek());
if(dataList.isEmpty() || dataList.getLast()<minValue || dataList.getLast()>maxValue){
return null;
}
TreeNode root = new TreeNode(dataList.removeLast());
root.right = dePostOrder(root.val, maxValue, dataList);
root.left = dePostOrder(minValue, root.val, dataList);
return root;
}
4-python中global的用法
-
背景:46. 全排列
-
总结:全局变量如果使用global在局部初始化,不要忘记赋初值
-
在类方法的局部函数中进行全局计数,可以采用设置全局变量和设置实例变量(实例变量相当于对象中的全局变量,而且用于对象中的局部函数还不用global、nonlocal修饰),这两种方式。
-
1,一段会报错的代码
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
length = len(nums)
count = 0 #这里的count只是定义在类的方法中的一个局部变量,不是全局变量(局部变量count有初值0,全局变量count没有)
def backtrack(track, choiceList):
global count #就算这里将count使用global修饰,但是全局变量count未赋值
count += 1 #由于count未赋值,所以报错
print('>'*self.count, track)
if len(track) == length:
result.append(copy.copy(track)) #如果直接使用result.append(track),最后result中的是同一个track
self.count -= 1
print('>'*self.count, 'return', track)
return
for num in choiceList:
track.append(num)
choiceList.remove(num)
backtrack(track, choiceList)
track.remove(num)
choiceList.append(num)
backtrack([], nums)
return result
- 修改方法1
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
length = len(nums)
global count #将局部变量count设置为全局变量
count = 0 #给全局变量count赋初值
def backtrack(track, choiceList):
global count #将count使用global修饰
count += 1 #由于count有初始赋值,所以不会报错
print('>'*count, track)
if len(track) == length:
result.append(copy.copy(track))
count -= 1
print('>'*count, 'return', track)
return
for num in choiceList:
track.append(num)
choiceList.remove(num)
backtrack(track, choiceList)
track.remove(num)
choiceList.append(num)
backtrack([], nums)
return result
- 修改方法2
count = 0 #这一步相当于设置全局变量count,并赋初值0
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
length = len(nums)
def backtrack(track, choiceList):
global count #将count使用global修饰
count += 1 #由于count有初始赋值,所以不会报错
print('>'*count, track)
if len(track) == length:
result.append(copy.copy(track))
count -= 1
print('>'*count, 'return', track)
return
for num in choiceList:
track.append(num)
choiceList.remove(num)
backtrack(track, choiceList)
track.remove(num)
choiceList.append(num)
backtrack([], nums)
return result
- 修改方法3
import copy
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
length = len(nums)
self.count = 0 #将count定义为实例变量
def backtrack(track, choiceList):
self.count += 1 #使用实例变量进行计数
print('>'*self.count, 'track', track)
print('>'*self.count, 'choiceList', choiceList)
if len(track) == length:
result.append(copy.copy(track))
self.count -= 1
print('>'*self.count, 'return', track)
print('>'*self.count, 'result', result)
return
for num in choiceList:
track.append(num)
choiceList.remove(num)
backtrack(track, choiceList)
track.remove(num)
choiceList.append(num)
backtrack([], nums)
print(result)
return result
5-java中的split
- split() 方法根据匹配给定的正则表达式来拆分字符串。
- 注意:
.
、$
、|
和*
等转义字符,必须得加\\
。(比如拆分ip的时候) - 注意:多个分隔符,可以用
|
作为连字符。 - 注意:分割符在最末尾,在分割结果中是没有体现的,所以如果有影响要判断一下。
- 比如"2001:0db8:85a3:0:0:8A2E:0370:7334:",在判断是否为IPV6时,如果用":"分割,最后一个":"不提前判断,split后在分割结果中是没有体现的
- 总结:split的结果除了末尾的分割符外,结果的长度等于分割符的数目+1;两个字符串之间间隔(连续的分割符数目-1)个空字符串。比如:
String c = "00002300002002020000";
System.out.println(Arrays.toString(c.split("0")));
System.out.println(c.split("0").length);
- 注意:
startWith
,endsWith
不用转义 - 468. 验证IP地址,自己菜鸡,这题还是很锻炼人的
6-java中的Integer.valueOf指定基数
Integer.valueOf(String "***", int *)
- 如果字符串中的字符超出基数范围,抛出异常
java.lang.NumberFormatException
- 字符串是可以带负号的
- 如果输入空字符串,抛出异常
java.lang.NumberFormatException
- 如果字符串中的字符超出基数范围,抛出异常
- 例子:
System.out.println(Integer.valueOf("0fb8", 16));
System.out.println(Integer.valueOf("0gb8", 16));
7-java实现精确的小数运算
- 一旦使用
float
或者double
,那么就意味着和精确没有关系了;如果要精确运算,请用java.math.BigDecimal
- 创建:
BigDecimal
变量:BigDecimal data = BigDecimal.valueOf(***)
- 导入:
import java.math.BigDecimal;
- valueOf输入一般为
long
或者double
类型的数值,不能是String
- 导入:
- 运算:
BigDecimal
变量只能与BigDecimal
进行加add
、减subtract
、乘multiply
、除divide
。- 出发注意是无限小数时,如果不指定舍入方式会报错
Non-terminating decimal expansion; no exact representable decimal result.
,正确用法为num1.divide(num2, RoundingMode.HALF_UP)
,或者num1.divide(num2, BidDecimal.Round_HALF_UP)
(就是前面加个ROUND_
) - 导入:
import java.math.RoundingMode
,如果用BigDecimal
的不用额外导入 - java常用舍入法
- ROUND_UP:远离零方向舍入。向绝对值最大的方向舍入,只要舍弃位非0即进位。
- ROUND_DOWN:趋向零方向舍入。向绝对值最小的方向输入,所有的位都要舍弃,不存在进位情况。
- ROUND_CEILING:向正无穷方向舍入。向正最大方向靠拢。若是正数,舍入行为类似于ROUND_UP,若为负数,舍入行为类似于ROUND_DOWN。Math.round()方法就是使用的此模式。
- ROUND_FLOOR:向负无穷方向舍入。向负无穷方向靠拢。若是正数,舍入行为类似于ROUND_DOWN;若为负数,舍入行为类似于ROUND_UP。
- ROUND_HALF_UP:最近数字舍入(5进)。这是我们最经典的四舍五入。
- ROUND_HALF_DOWN:最近数字舍入(5舍)。在这里5是要舍弃的。
- ROUND_HAIL_EVEN:银行家舍入法。
- 出发注意是无限小数时,如果不指定舍入方式会报错
- 指定小数位:
setScale(2, BigDecimal.ROUND_HALF_UP)
,分别填入小数点后保留几位,以及舍入方式。 - 例题:
6079. 价格减免
8-java使用分割符连接字符串-StringJoiner
import java.util.StringJoiner;
StringJoiner sj = new StringJoiner("-");
sj.add("100");
sj.add("200");
System.out.println(sj.toString());
行动是治愈恐惧的良药,而犹豫拖延将不断滋养恐惧。