The String ||

本文详细探讨了代码优化的技巧与算法的核心应用,包括但不限于动态规划、DFS、回文串查找、最长公共子串等。通过实例分析,展示了如何高效解决复杂问题并提升程序性能。
挺综合的一道题目,核心方法是NP的DFS。 回头应当做俩遍
实现中需要一个判断数字是否为合法ip地址的一项的函数,首先要在0-255之间,其次前面字符不能是0。剩下的就是 NP问题 的套路了,递归中套一个for循环,不熟悉的朋友可以看看 N-Queens 哈。
--Code Ganker

//update my own version
    public List
  
    restoreIpAddresses(String s) {
         List
   
     res = new ArrayList
    
     ();
         helper(res,"",s,0,0);
         return res;
    }
    public void helper( List
     
       res, String item, String s, int start, int count){
        if(start == s.length() && count == 4){
            res.add(item);
            return;
        }
        if(count >= 4 || start == s.length())
            return;
        if(s.charAt(start) == '0'){
            String newItem = start==s.length()-1 ? item + s.substring(start, start+1) : item + s.substring(start, start+1) + ".";
            helper(res,newItem,s,start+1,count+1);
            return;
        }
        
        for(int i= start; i
      
        restoreIpAddresses(String s) {
        List
       
         res = new ArrayList
        
         (); if(s == null || s.length() == 0 || s.length() > 12) return res; helper(res,s,"",0,1); return res; } public void helper(List
         
           res, String s, String temp, int index, int segment){ if(index > s.length() - 1){ return; } if(segment == 4){ String seg4 = s.substring(index); if(isValid(seg4)){ res.add(temp+"."+ seg4); } return; } for(int i=1;i<4 && index + i < s.length();i++){ String seg = s.substring(index,index+i); if(isValid(seg)){ if(segment == 1){ helper(res,s,seg,index+i,segment+1); }else{ helper(res,s,temp+"."+seg,index+i,segment+1); } } } } public boolean isValid(String str){ if(str.length() > 3) return false; if(str.charAt(0) == '0' && str.length() > 1) return false; int strInt = Integer.parseInt(str); if( strInt >= 0 && strInt <= 255) return true; return false; } }
         
        
       
      
     
    
   
  

算法题目是很有意思的一个东西,很喜欢一句话,应该就是算法所追求的哲学 less is more 。 正确的数据结构和变量的使用十分重要,能不能找到问题的实质,而非处理纷杂的表象。Code Ganker的代码不论长短,总是能揭示实质。与其它几位大神的code相比,我个人认为是要高出一个段位点。

这也是一道brain fuck的题目,我梳理一下我使用stack时候遇到的问题。
1. stack.isEmpty()的检查等价于 count_left  这个变量点,我一开始又重复使用了这个变量来计数剩余左括号。
2. 最终承上启下的变量用的是start,我找了很久没确定对这个变量,我使用了 last_end  , origin(类似start) 这俩个变量,这里的问题是,不可以从表象与个例中着手定义变量,last_end 这种廉价的变量显然是为了折中的处理 “()()()()” 这种情况,我一开始误判为这是一个累加点过程 2+2+2+2。
3. start用的巧妙,但从start入手难理解此题真谛,这个题的核心逻辑是 stack.peek() 所揭示的。我在做的时候,int index = stack.pop(), 然后在 - stack.peek()的位置使用了- index + 1. 这也是我这道题最大的启发,说俩点 1. 有些时候 二者是相等的,有些时候不等。而stack.peek()总是包含了index-1 的情况的,所以更优。2. 之前为何要用到一个变量start?因为我们要用的是peek(), 当stack为空时,没有peek()可以call, 我们用start-1代替,实际上start-1的意义正是stack.peek()

"(()()"这种情况,必须用peek(), 用index -1 就不对了。还是说,index-1是表象的巧合,而peek()才是问题的实质。

public class Solution {
    public int longestValidParentheses(String s) {
        LinkedList
   
     stack = new LinkedList
    
     ();
        int start = 0;
        int res = 0;
        for(int i=0; i
     
    
   

this one is definitely the most heart fucking one ever and never. I spent 5 hours on this medium problem... And failed submission more than 50 times...
Mother Fucker...
Any thing about math trick, kills me. 
Ironically I don't even know the rule of multiplication. when use index, i for index of num1, j for index of num2, and i = 0 is the first entry of num1, if we arrange the number as one,ten,hundred,...  , then we have the following fact, for the i th entry(ith smallest, 0th entry is one, 1th entry is ten...), it comes from  mth entry from num1, and (i-m)th entry from num2 if valid.
这个乘法看起来每乘一位是进位相加,其实这个进位是自动进行的,因为第一个乘数 j 进了一位, i+j自然跟着进了一位。
FUCK...
public class Solution {
      public String multiply(String num1, String num2) {
        if(num1.charAt(0) == '0' || num2.charAt(0) == '0'){
            return "0";
        }
        StringBuilder sb1 = new StringBuilder(num1);
        StringBuilder sb2 = new StringBuilder(num2);
        String rnum1 = sb1.reverse().toString();
        String rnum2 = sb2.reverse().toString();
        int[] res = new int[num1.length() + num2.length()];
        int carry = 0;
        for(int i=0; i
  

像这种判断能否按照某种规则来完成求是否或者某个量的题目,很容易会想到用动态规划来实现。
先说说维护量,res[i][j]表示用s1的前i个字符和s2的前j个字符能不能按照规则表示出s3的前i+j个字符,如此最后结果就是res[s1.length()][s2.length()],判断是否为真即可。接下来就是递推式了,假设知道res[i][j]之前的所有历史信息,我们怎么得到res[i][j]。可以看出,其实只有两种方式来递推,一种是选取s1的字符作为s3新加进来的字符,另一种是选s2的字符作为新进字符。而要看看能不能选取,就是判断s1(s2)的第i(j)个字符是否与s3的i+j个字符相等。如果可以选取并且对应的res[i-1][j](res[i][j-1])也为真,就说明s3的i+j个字符可以被表示。这两种情况只要有一种成立,就说明res[i][j]为真,是一个或的关系。所以递推式可以表示成
res[i][j] = res[i-1][j]&&s1.charAt(i-1)==s3.charAt(i+j-1) || res[i][j-1]&&s2.charAt(j-1)==s3.charAt(i+j-1)
-- Code Ganker
感觉DP快到火候了,继续。

不过遇到这种题总喜欢用recursion解一下,总觉得recursion更有意思。这里用到之前用过的一种预判,如果排序后的s1+s2   不等于排序后的 s3, 那么直接返回false。但是还是TLE了 :(
public class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        if(s1 == null || s2 == null)
            return false;
        if(s3.length() != s1.length() + s2.length())
            return false;
        boolean[][] dp = new boolean[s1.length()+1][s2.length()+1];
        dp[0][0] = true;
        for(int i=1;i<=s2.length();i++){
            if(s2.substring(0,i).equals(s3.substring(0,i))){
                dp[0][i] = true;
            }
        }
        for(int i=1;i<=s1.length();i++){
            if(s1.substring(0,i).equals(s3.substring(0,i))){
                dp[i][0] = true;
            }
        }
        for(int i=1;i<=s1.length();i++){
            for(int j=1;j<=s2.length();j++){
                if(dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1) || dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1)){
                    dp[i][j] = true;
                }
            }
        }
        return dp[s1.length()][s2.length()];
    }
}


//Recursion
public class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        if(s1.length() + s2.length() != s3.length())
            return false;
        char[] c1 = new char[s3.length()];
        char[] c2 = new char[s3.length()];
        for(int i =0; i
   

这个题目是一道很有学习价值的DP题目,应该放在DP章节专门整理,承上启下。
简要的记录几点思路过程。
1.  abbabba  对于这样一个回文,很自然的递推关系 :  bbabb是回文, 并且 abbabba 俩头相等,即a==a 此处。这个递推关系用坐标表示呢?
dp[i][j]   取决于 dp[i+1][j-1]
2. 一个隐含关系:i <= j   , 暗示了矩阵打右上角。
3. 根据地推关系,i 依赖于 i+1  , 即 i 的下一行 ; j 依赖于 j-1, 即j到前一列。 这暗示了扫描要从下往上,从左向右。

4. 一个小trick,注意递推条件 j-i <= 2的使用。原因画出矩阵便清楚了。第一(对角线列) 二斜列是没有历史信息可用的。


public class Solution {
public String longestPalindrome(String s) {
    if(s == null)
        return "";
    boolean[][] dp = new boolean[s.length()][s.length()];
    String res = "";
    for(int i=s.length()-1;i>=0;i--){
        for(int j=i;j
   
     res.length()){
                    res = s.substring(i,j+1);
                }
            }
        }
    }
    return res;
    }
}

//Another way, in case I forgot DP
public String longestPalindrome(String s) {
    int left; 
    int right;
    String res = "";
    String temp;
    for(int i=0;i
    
      res.length()){
            res = temp;
        }
        if(right+1 < s.length()){
            temp =  isPalindrome(s,left,right+1);
            if( temp.length() > res.length()){
                res = temp;
            }
        }
    }
    return res;
}

public String isPalindrome(String s, int left, int right){
    while(left >= 0 && right <= s.length()-1 && s.charAt(left) == s.charAt(right)){
        left --;
        right ++;
    }
    return s.substring(left+1,right);
}
    
   



滑动窗口的题目,用到了hashset来判别重复。空间换时间。
longest 这种string 的题目,不是dp就是双指针滑动窗口??

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s == null)
            return 0;
        int res = 0;
        HashSet
   
     set = new HashSet
    
     ();
        int left = 0;
        int right = 0;
        for(right=0; right
     
    
   



这个题不喜欢,java 的时间卡的太严,相同思路换换实现就过不了。直接看友链记住好了。
作为滑动窗口的题目,似乎又有点太偏。code ganker有一种滑动窗口的解法,第三遍但时候研究下。


Brain Fuck... An exciting sliding window challenge. Notice how "count" is maintained. it expands as right move, and shrinks as left move, but not necessarily. And the condition of 
modifying "count" is very question specific and is implemented by a HashMap here.
public class Solution {
    public String minWindow(String s, String t) {
        if(s == null || t ==null || s.length() ==0 || s.length() < t.length())
            return "";
        HashMap
   
     map = new HashMap
    
     ();
        for(char c : t.toCharArray()){
            if(!map.containsKey(c)){
                map.put(c,1);
            }else{
                map.put(c, map.get(c)+1);
            }
        }
        int count = 0;
        int right = 0;
        int left = 0;
        int minStart = 0;
        int min = s.length() + 1;
        for(right=0;right
     
      = 0){
                    //每个T中的char只出现一次,出现多次也不计入count
                    count ++;
                }
                while(count == t.length()){
                    if(right - left + 1 < min){
                        min = right - left + 1;
                        minStart = left;
                    }
                    if(map.containsKey(s.charAt(left))){
                        map.put(s.charAt(left), map.get(s.charAt(left)) + 1 );
                        if(map.get(s.charAt(left)) > 0){
                        //对应count++的操作。多余的出现视为不在T内,所以都要跳过。
                            count --;
                        }
                    }
                    left++;                    
                }
            }
        }
        
    if(min>s.length()) //这种检查总是有益无害的 
        return "";  
    return s.substring(minStart,minStart+min);
    }
}
     
    
   





<think>我们有一个类型错误:尝试将 `HashMap<string, SmartDetectionBean>` 传递给期望 `Map<string, string | number | object | SmartDetectionBean>` 类型的参数。 错误信息指出:`HashMap` 类型不能赋值给 `Map` 类型。 可能的原因: 1. `HashMap` 类可能不是 TypeScript 内置的 `Map` 类的子类或兼容类型。 2. 类型 `SmartDetectionBean` 可能不能赋值给联合类型 `string | number | object | SmartDetectionBean`?实际上,因为 `SmartDetectionBean` 是联合类型中的一员,所以这个联合类型应该包含 `SmartDetectionBean`。因此,问题可能在于 `HashMap` 与 `Map` 不兼容。 解决方案: 我们需要确保 `HashMap` 与 `Map` 在类型上是兼容的。由于 TypeScript 是结构类型系统,如果 `HashMap` 具有与 `Map` 相同的结构(即相同的方法和属性),那么它们就是兼容的。 但是,如果 `HashMap` 是我们自定义的类,它可能没有实现 `Map` 接口的所有方法,或者它的实例方法签名不完全匹配。 步骤: 1. 检查 `HashMap` 类的定义,确保它实现了与 `Map` 相同的接口(包括方法:`get`, `set`, `has`, `delete`, `clear`, `size` 属性等)。 2. 如果 `HashMap` 确实实现了 `Map` 的所有方法,那么可能是因为 TypeScript 无法识别它们之间的兼容性。我们可以尝试使用类型断言(`as`)来强制转换类型,但这可能会掩盖真正的问题。 3. 更好的做法是让 `HashMap` 类实现 `Map` 接口。例如: ```typescript class HashMap<K, V> implements Map<K, V> { // ... 实现所有Map要求的方法和属性 } ``` 4. 如果无法修改 `HashMap` 的源代码,我们可以考虑创建一个适配器函数,将 `HashMap` 转换为 `Map`。 但是,根据错误信息,我们注意到目标参数的类型是 `Map<string, string | number | object | SmartDetectionBean>`,而我们的 `HashMap` 是 `HashMap<string, SmartDetectionBean>`。虽然 `SmartDetectionBean` 是目标值类型联合中的一部分,但目标值类型联合还包括了其他类型(`string | number | object`)。因此,即使 `HashMap` 的值类型是 `SmartDetectionBean`,它也不能赋值给要求值类型为联合类型的 `Map`,因为 `Map` 的值类型是协变的(在TypeScript中,对于泛型类,类型参数是协变的,但这里我们要求的是值类型更宽泛的Map)。 实际上,在TypeScript中,`Map<string, SmartDetectionBean>` 是可以赋值给 `Map<string, string | number | object | SmartDetectionBean>` 的,因为 `SmartDetectionBean` 是 `string | number | object | SmartDetectionBean` 的子类型(更具体)。所以,这个赋值在类型理论上是安全的。 因此,问题可能出在 `HashMap` 类本身不是 `Map` 的兼容类型。 让我们重新审视错误信息: "Argument of type 'HashMap<string, SmartDetectionBean>' is not assignable to parameter of type 'Map<string, string | number | object | SmartDetectionBean>'" 这意味着 `HashMap` 不能赋值给 `Map`。所以,我们需要让 `HashMap` 类与 `Map` 兼容。 如何修复: 方案1:修改 `HashMap` 使其继承自 `Map` 或实现 `Map` 接口。 方案2:如果无法修改 `HashMap`,我们可以创建一个新的 `Map` 实例,并将 `HashMap` 的所有键值对复制到该 `Map` 中。 例如: ```typescript const myHashMap = new HashMap<string, SmartDetectionBean>(); // ... 填充 myHashMap // 创建一个新的Map,其类型为目标类型 const map = new Map<string, string | number | object | SmartDetectionBean>(); myHashMap.forEach((value, key) => { map.set(key, value); }); // 然后传递这个map someFunctionThatExpectsMap(map); ``` 方案3:如果 `HashMap` 的结构与 `Map` 足够相似(即具有相同的方法和属性),我们可以使用类型断言来告诉TypeScript我们认为它是兼容的: ```typescript someFunctionThatExpectsMap(myHashMap as unknown as Map<string, string | number | object | SmartDetectionBean>); ``` 但是,这种方法不安全,因为如果 `HashMap` 缺少某些方法,运行时可能会出错。 建议: 如果 `HashMap` 是自定义的,并且我们能够修改它的代码,最好让它实现 `Map` 接口。这样,它就可以在任何需要 `Map` 的地方使用。 如果 `HashMap` 来自第三方库,查看其文档,看它是否设计为与 `Map` 兼容。如果不兼容,则使用方案2(复制到一个新的Map中)是最安全的方法。 根据你的具体场景,选择合适的方法。 相关问题: 1. 如何在TypeScript中实现一个自定义的Map类? 2. TypeScript中泛型的协变和逆变是什么? 3. 如何将自定义集合类转换为TypeScript内置的Map? 4. TypeScript类型断言的使用场景和风险?</think>### 解决 TypeScript 类型不匹配错误 #### 问题分析 错误信息 `Argument of type 'HashMap<string, SmartDetectionBean>' is not assignable to parameter of type 'Map<string, string | number | object | SmartDetectionBean>'` 表明: 1. 您尝试将 `HashMap` 类型传递给期望 `Map` 类型的函数 2. `HashMap` 的泛型参数与目标 `Map` 的泛型约束不兼容 3. TypeScript 认为 `HashMap` 不是 `Map` 的子类型 #### 解决方案 ##### 1. 类型断言(快速修复) ```typescript const myHashMap = new HashMap<string, SmartDetectionBean>(); const targetMap = myHashMap as unknown as Map<string, string | number | object | SmartDetectionBean>; yourFunction(targetMap); // 现在可以通过类型检查 ``` * **优点**:快速绕过类型检查 * **风险**:可能掩盖实际类型问题,需确保运行时类型安全 ##### 2. 实现适配器模式 ```typescript class HashMapAdapter { static toMap<K, V>(hashMap: HashMap<K, V>): Map<K, V | string | number | object> { const map = new Map<K, V | string | number | object>(); hashMap.forEach((value, key) => { map.set(key, value); }); return map; } } // 使用方式 const convertedMap = HashMapAdapter.toMap(myHashMap); yourFunction(convertedMap); ``` * **优点**:类型安全,明确处理类型转换 * **推荐**:适用于需要复用转换逻辑的场景 ##### 3. 修改目标函数签名(推荐) ```typescript // 原始函数 function yourFunction(map: Map<string, string | number | object | SmartDetectionBean>) { // ... } // 修改为泛型函数 function yourFunction<T extends string | number | object | SmartDetectionBean>( map: Map<string, T> ) { // ... } ``` * **优点**:从根源解决类型约束问题 * **适用**:当您能控制目标函数代码时 ##### 4. 扩展 HashMap 类型声明 在类型声明文件中(如 `global.d.ts`): ```typescript declare global { interface HashMap<K, V> extends Map<K, V> { // 添加实际实现的方法声明 customMethod?(): void; } } ``` * **作用**:明确告知 TypeScript `HashMap` 是 `Map` 的子类型 * **要求**:需确保 `HashMap` 实际实现了 `Map` 的所有方法 #### 关键注意事项 1. **类型兼容性**:检查 `HashMap` 是否确实实现了 `Map` 的所有接口方法(`get`, `set`, `has`, `entries` 等) 2. **泛型约束**:确认 `SmartDetectionBean` 是否满足 `string | number | object` 的约束 3. **运行时行为**:即使通过类型检查,也需验证 `HashMap` 在运行时是否与 `Map` 行为一致 #### 最佳实践建议 ```typescript // 1. 使用类型守卫确保安全 if (isValidMap(myHashMap)) { yourFunction(myHashMap); } // 2. 实现类型守卫函数 function isValidMap(obj: any): obj is Map<string, string | number | object | SmartDetectionBean> { return obj instanceof Map && typeof obj.set === 'function'; } // 3. 优先使用标准Map替代HashMap(如可行) const standardMap = new Map<string, SmartDetectionBean>(); yourFunction(standardMap as Map<string, string | number | object | SmartDetectionBean>); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值