字符的统计——423、657、551、696、467、535

423. 从英文中重建数字

最初思路

首先要有一个指针,对于3/4/5为一组地跳跃。起初想的是后瞻性,如果符合0-9任意,则更换index、跳跃。此时写了一个函数,用来判断s的截取段和0-9中有无符合。这个思路并没有进行下去,虽然可行,但满地补丁、没有美感,代码量和耗时耗空间量实在太大了。

顺便一提,除了two和six的ascii码量相同外,其他的都各自不同。也可以通过这个来比较,额外判断一下是two还是six。

java 复制代码
    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里取出偶数放前面很重要

java 复制代码
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出现的次数一致。

java 复制代码
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的情况,分别是计数和后视两位

java 复制代码
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

java 复制代码
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个最小子串

java 复制代码
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

java 复制代码
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"然后向外扩展

java 复制代码
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)

java 复制代码
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 的加密与解密

解法一、不讲武德

双百通关。本来就是想试试,没想到真可以。假如人与人之间多一点信任。。

java 复制代码
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

java 复制代码
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−1​longUrl[i]×k1i​)modk2​

java 复制代码
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每天都能打卡固然很厉害,断了一天后没彻底摆烂也很重要啊!共勉~

六道题写了两小时一刻钟,其中还有不少是看了题解。

相关推荐
wheeldown7 小时前
【数据结构】选择排序
数据结构·算法·排序算法
躺不平的理查德11 小时前
数据结构-链表【chapter1】【c语言版】
c语言·开发语言·数据结构·链表·visual studio
阿洵Rain11 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法
Leo.yuan11 小时前
39页PDF | 华为数据架构建设交流材料(限免下载)
数据结构·华为
半夜不咋不困11 小时前
单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构
数据结构·链表
忘梓.12 小时前
排序的秘密(1)——排序简介以及插入排序
数据结构·c++·算法·排序算法
y_m_h15 小时前
leetcode912.排序数组的题解
数据结构·算法
1 9 J15 小时前
数据结构 C/C++(实验三:队列)
c语言·数据结构·c++·算法
921正在学习编程15 小时前
数据结构之二叉树前序,中序,后序习题分析(递归图)
c语言·数据结构·算法·二叉树
毕竟秋山澪15 小时前
岛屿数量 广搜版BFS C#
数据结构·算法·宽度优先