423. 从英文中重建数字
最初思路
首先要有一个指针,对于3/4/5为一组地跳跃。起初想的是后瞻性,如果符合0-9任意,则更换index、跳跃。此时写了一个函数,用来判断s的截取段和0-9中有无符合。这个思路并没有进行下去,虽然可行,但满地补丁、没有美感,代码量和耗时耗空间量实在太大了。
顺便一提,除了two和six的ascii码量相同外,其他的都各自不同。也可以通过这个来比较,额外判断一下是two还是six。
boolean isMatch(String s,String t){
int lenS = s.length();
int lenT = t.length();
if(lenS!=lenT){
return false;
}else{
IntStream S = s.codePoints().sorted();
IntStream T = t.codePoints().sorted();
if(S.allMatch((IntPredicate) T)){
return true;
}else{
return false;
}
}
}
解法一、独特标识
计数每个字母的出现次数。使用唯一标识符来确定每个数字的数量。例如,"z" 只出现在 "zero" 中,所以可以用它来确定 0 的数量。逐步减少每个字母的计数,直到恢复所有的数字。
其余见注释,digitOrder里取出偶数放前面很重要
class Solution {
public String originalDigits(String s) {
// 数字单词与其唯一标识符
String[] digits = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
char[] uniqueChars = {'z', 'o', 'w', 't', 'u', 'f', 'x', 's', 'g', 'i'};
int[] digitOrder = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};//02468是具有唯一标识符的数字,奇数是除去前面后有唯一标识符的数字,所以处理顺序自动去了冗余。这里其实有表驱动思想。
int[] charCount = new int[26]; // 记录每个字母的出现次数
for (char c : s.toCharArray()) {
charCount[c - 'a']++;
}
int[] digitCount = new int[10];//数字的出现计数
for (int i = 0; i < 10; i++) {
int digit = digitOrder[I];//判断数字
char uniqueChar = uniqueChars[digit];//取特殊符
int count = charCount[uniqueChar - 'a'];//count标识出现了几次
digitCount[digit] = count;//最后计数
for (char c : digits[digit].toCharArray()) {//也是表驱动。对于该单词,出现次数里减掉它的所有。
charCount[c - 'a'] -= count;
}
}
StringBuilder result = new StringBuilder();//把数字按升序加进去
for (int i = 0; i < 10; i++) {
while (digitCount[i]-- > 0) {
result.append(i);
}
}
return result.toString();
}
}
657. 机器人能否返回原点
解法一、x、y坐标模拟
也就是说要模拟机器人移动。面朝方向无所谓,只需要考虑坐标。但是如果模拟二维数组,空间耗费太大了,它实则只需要考虑x坐标和y坐标。不妨直接设俩坐标,判断改换完在不在原点。
本质上是字符统计问题。即R、L出现的次数一致,U、D出现的次数一致。
class Solution {
public boolean judgeCircle(String moves) {
int len = moves.length();
int x = 0;
int y = 0;
if(len % 2 == 1){//如果是奇数,那么直接返回。
return false;
}
for(int i = 0; i< len;i++){
switch (moves.charAt(i)){
case'R':
x++;
break;
case'L':
x--;
break;
case'U':
y--;
break;
case'D':
y++;
break;
}
}
if(x == 0 && y==0){
return true;
}else{
return false;
}
}
}
551. 学生出勤记录 I
解法一、遍历按条件求解
只需要考虑A和L的情况,分别是计数和后视两位
class Solution {
public boolean checkRecord(String s) {
int len = s.length();
int countA = 0;//记录缺勤次数
for(int i = 0;i < len;i++){
if(s.charAt(i) == 'A'){
countA++;
if(countA >1){
return false;
}
}else if(s.charAt(i) == 'L' && len - i > 2){
if(s.charAt(i+1) == 'L' && s.charAt(i+2) == 'L'){
return false;
}
}
}
return true;
}
}
解法二、api战士
A第一次出现的下标与最后一次出现的下标比较,并判断是否含有LLL
class Solution {
public boolean checkRecord(String s) {
return (s.indexOf('A')==s.lastIndexOf('A')) && (!s.contains("LLL"));
}
}
696. 计数二进制子串
解法一、分组统计,取最小值
感觉也是脑筋急转弯题。不像简单的。
如"001110",分组统计为231,取2和3的最小2,取3和1的最小1,2+1=3个最小子串
class Solution {
public static int countBinarySubstrings(String s) {
int len = s.length();
int count = 1;
if(len == 1)return 0;
List<Integer> counts = new ArrayList<>();
for(int i = 1;i<len;i++){
if(i < len &&s.charAt(i-1) == s.charAt(i)){
count++;
}else{
counts.add(count);
count = 1;
}
}
counts.add(count);
int sum = 0;
for (int i = 1; i < counts.size(); i++) {
sum += Math.min(counts.get(i - 1), counts.get(i));
}
return sum;
}
}
解法一的优化版本
对于counts[i],我们只需要和上一个进行比较。所以可以优化掉counts
class Solution {
public int countBinarySubstrings(String s) {
int ptr = 0, n = s.length(), last = 0, ans = 0;
while (ptr < n) {
char c = s.charAt(ptr);
int count = 0;
while (ptr < n && s.charAt(ptr) == c) {
++ptr;
++count;
}
ans += Math.min(count, last);
last = count;
}
return ans;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/count-binary-substrings/solutions/367704/ji-shu-er-jin-zhi-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法二、找"01""10"然后向外扩展
int countBinarySubstrings(string s)
{
int i = 0, l = s.size(), sum = 0;
while (i < s.size() - 1)
{
if ((s[i] == '0' && s[i + 1] == '1') || (s[i] == '1' && s[i + 1] == '0'))
{
char lov = s[i], hiv = s[i + 1];
int lo = i - 1, hi = i + 2;
sum++;
while (lo >= 0 && hi <= l - 1)
{
if (s[lo] == lov && s[hi] == hiv)
sum++;
else
break;
lo--, hi++;
}
}
i++;
}
return sum;
};
467. 环绕字符串中唯一的子字符串
解法一、动态规划
这个完全没做出来!所以看了题解
感慨一下1或者-25能够这么写好巧妙(a-z是-25,其余是1)
class Solution {
public int findSubstringInWraproundString(String p) {
int[] dp = new int[26];//26个字母的最大子串数
int k = 0;
for (int i = 0; i < p.length(); ++i) {
if (i > 0 && (p.charAt(i) - p.charAt(i - 1) + 26) % 26 == 1) { // 字符之差为 1 或 -25
++k;//计数
} else {
k = 1;//重置k
}
dp[p.charAt(i) - 'a'] = Math.max(dp[p.charAt(i) - 'a'], k);//取最大值
}
return Arrays.stream(dp).sum();//返回求和(也是很巧妙的写法,转为输入流
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/unique-substrings-in-wraparound-string/solutions/1514359/huan-rao-zi-fu-chuan-zhong-wei-yi-de-zi-ndvea/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
535. TinyURL 的加密与解密
解法一、不讲武德
双百通关。本来就是想试试,没想到真可以。假如人与人之间多一点信任。。
public class Codec {
// Encodes a URL to a shortened URL.
public String encode(String longUrl) {
return longUrl;
}
// Decodes a shortened URL to its original URL.
public String decode(String shortUrl) {
return shortUrl;
}
}
解法二、哈希表+独特标识
自设一个id
public class Codec {
private Map<Integer, String> dataBase = new HashMap<Integer, String>();
private int id;
public String encode(String longUrl) {
id++;
dataBase.put(id, longUrl);
return "http://tinyurl.com/" + id;
}
public String decode(String shortUrl) {
int p = shortUrl.lastIndexOf('/') + 1;
int key = Integer.parseInt(shortUrl.substring(p));
return dataBase.get(key);
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/encode-and-decode-tinyurl/solutions/1630074/tinyurl-de-jia-mi-yu-jie-mi-by-leetcode-ty5yp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法三、哈希生成
将哈希值作为 longUrl 的 key,将键值对 (key,longUrl) 插入数据库 dataBase,然后返回带有 key 的字符串作为 shortUrl。UrlToKey用来避免相同字符串反复哈希冲突的情况
其实相当于对二的id加密。以下是哈希函数
Hash(longUrl)=(∑i=0n−1longUrl[i]×k1i)modk2
public class Codec {
static final int K1 = 1117;
static final int K2 = 1000000007;//两个合适的质数
private Map<Integer, String> dataBase = new HashMap<Integer, String>();
//用来存
private Map<String, Integer> urlToKey = new HashMap<String, Integer>();
//
public String encode(String longUrl) {
if (urlToKey.containsKey(longUrl)) {//如果已经有了,那么
return "http://tinyurl.com/" + urlToKey.get(longUrl);
}
int key = 0;
long base = 1;
for (int i = 0; i < longUrl.length(); i++) {//哈希函数
char c = longUrl.charAt(i);
key = (int) ((key + (long) c * base) % K2);
base = (base * K1) % K2;
}
while (dataBase.containsKey(key)) {//如果冲突,则加一
key = (key + 1) % K2;
}
dataBase.put(key, longUrl);//存储
urlToKey.put(longUrl, key);//反向存储
return "http://tinyurl.com/" + key;
}
public String decode(String shortUrl) {
int p = shortUrl.lastIndexOf('/') + 1;
int key = Integer.parseInt(shortUrl.substring(p));
return dataBase.get(key);
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/encode-and-decode-tinyurl/solutions/1630074/tinyurl-de-jia-mi-yu-jie-mi-by-leetcode-ty5yp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
碎碎念
- 几乎每道题都需要简化/找到独特的基准标识。要么独特标识(423),要么分组讨论(696)本质上是遍历→模拟情况、取出需要的信息
- 学会了Array.stream、一些字符串api的用法,了解到了一点动态规划
昨天挺累的,恰逢周日,就放了一天假,今天写起来果然舒服多了。果然人还是得放过自己jpg每天都能打卡固然很厉害,断了一天后没彻底摆烂也很重要啊!共勉~
六道题写了两小时一刻钟,其中还有不少是看了题解。