Leetcode 131-140刷题笔记(非困难题目)

131.分割回文串

该题目使用的是回溯法,在添加到集合前,我们需要判断一下是否为回文串,如果不是则不添加。

在是否为回文串我们可以采用动态规划的思想,对这个字符串进行一个预处理。

    //字符串拆分成回文子串
    public List<List<String>> partition(String s) {
        List<List<String>> lists = new ArrayList<>();
        if(s.length() == 0) {
            return lists;
        }
        //保存子串的回文串状态(动态规划)
        boolean[][] flag = new boolean[s.length()][s.length()];
        for(int right=0; right<flag.length; right++) {
            for(int left=0; left<= right; left++) {
                //代表只有一个元素的时候
                if(left == right) {
                    flag[left][right] = true;
                    continue;
                }
                //说明可以状态转移
                if(s.charAt(left) == s.charAt(right)) {
                    //如果长度 = 2,那么直接为true
                    if(right - left + 1 == 2) {
                        flag[left][right] = true;
                    }else {
                        flag[left][right] = flag[left + 1][right - 1];
                    }
                }
            }
        }

        backTrace(lists,new ArrayList<>(),s,flag,0);

        return lists;
    }

    public void backTrace(List<List<String>> lists, List<String> list, String s, boolean[][] flag, int index) {
        if(index == s.length()) {
            lists.add(new ArrayList<>(list));
            return;
        }


        //index是子串头字符,i为截取的尾巴位置字符
        for(int i=index; i<s.length(); i++) {
            if(flag[index][i]) {
                //右边开区间
                list.add(s.substring(index,i + 1));
                backTrace(lists, list, s, flag, i + 1);
                list.remove(list.size() - 1);
            }
        }
    }

133.克隆图

该题目就是一个深拷贝的题目,需要拷贝一个和原图一模一样,无关联的图。

该题目主要使用缓存的思想,将我们创建过的结点进行保存,如果缓存命中则取出,如果没有命中则重新创建。

public class Solution {
    //用于保存克隆后的结点
    Map<Integer,Node> map = new HashMap<>();

    //克隆图(深拷贝),属性List代表自己的邻居
    public Node cloneGraph(Node node) {
        if(node == null) {
            return null;
        }

        Node newNode = null;

        if(map.containsKey(node.val)) {
            return map.get(node.val);
        }else {
            newNode = new Node(node.val);
            map.put(node.val,newNode);
        }

        //获取与其相邻的结点
        List<Node> neighbors = node.neighbors;
        List<Node> newNeighbors = new ArrayList<>();

        for(Node neighbor : neighbors) {
            if(map.containsKey(neighbor.val)) {
                newNeighbors.add(map.get(neighbor.val));
            }else {
                newNeighbors.add(cloneGraph(neighbor));
            }
        }

        newNode.neighbors = newNeighbors;

        return newNode;
    }


}

134.加油站

该题目就是一个dfs的方式进行搜索,没有特别之处。

    //加油站(不能重复访问,并且只能向右边相邻位置进行访问)
    public int canCompleteCircuit(int[] gas, int[] cost) {
        for(int i=0; i<gas.length; i++) {
            // 说明可以从 i 出发
            if(gas[i] >= cost[i]) {
                if(dfs(gas,cost,i,gas[i],0)) {
                    return i;
                }
            }
        }

        //说明无法找到
        return -1;
    }

    public boolean dfs(int[] gas, int[] cost, int index, int nowGas, int times) {
        //说明能够环绕一周
        if(times == gas.length) {
            return true;
        }
        //计算当前油量
        nowGas += gas[index];
        //如果无法访问下一位,则说明失败
        if(nowGas < cost[index]) {
            return false;
        }
        //说明可以到达,重新计算剩余油量
        nowGas -= cost[index];

        //说明到尾巴了,需要从头部继续开始
        if(index + 1 >= gas.length) {
            index = -1;
        }
        
        //说明可以向后面访问
        return dfs(gas, cost, index + 1, nowGas, times + 1);
    }

136.只出现一次的数字

使用异或进行位运算。

    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }

137.只出现一次的数字2

该题目也可以使用常量空间复杂度,可以看题解,我这里使用的HashMap解决的(O(N))

  public int singleNumber(int[] nums) {
    HashMap<Integer, Integer> hashmap = new HashMap<>();
    for (int num : nums)
      hashmap.put(num, hashmap.getOrDefault(num, 0) + 1);

    for (int k : hashmap.keySet())
      if (hashmap.get(k) == 1) return k;
    return -1;
  }

138.复制带随机指针的链表

该题目和前面的拷贝题目类似,不过该题可能存在重复val,所以我们需要将Key换成对应的旧 node 结点,其他的旧类似,需要注意的就是需要先保存缓存在进行递归。

public class Solution {
    //(旧node , 拷贝node)
    Map<Node,Node> map = new HashMap<>();
    //深拷贝
    public Node copyRandomList(Node head) {
        if(head == null) {
            return null;
        }

        if(map.containsKey(head)) {
            return map.get(head);
        }

        Node newHead = new Node(head.val);
        //先存入缓存,在进行后面的访问(此时为不完整拷贝对象,不过先提前暴露)
        map.put(head,newHead);
        //这里填充的可能是不完成拷贝的对象,但是我们已经指向了他们对应的内存,之后递归结束就会完成对象的完全拷贝。
        newHead.next = copyRandomList(head.next);
        newHead.random = copyRandomList(head.random);

        return newHead;
    }
}

139.单词拆分

提供两种思路吧

1.dfs(超时)

    //单词拆分
    public boolean wordBreak(String s, List<String> wordDict) {
        return dfs(s,wordDict);
    }

    public boolean dfs(String s, List<String> wordDict) {
        if(s.length() == 0) {
            return true;
        }

        for(String word : wordDict) {
            if(s.startsWith(word)) {
                if(dfs(s.substring(word.length(),s.length()),wordDict)) {
                    return true;
                }
            }
        }

        return false;
    }

2.动态规划

    //单词拆分
    public boolean wordBreak(String s, List<String> wordDict) {
        //保存从下标0开始的对应长度是否有一种单词匹配方式
        boolean[] dp = new boolean[s.length() + 1];
        Set<String> set = new HashSet<>(wordDict);
        //初始化
        dp[0] = true;

        for(int len=1; len<dp.length; len++) {
            for(int start=0; start<len; start++) {
                //前start长度是否有对应匹配 && 后面部分字符串在词典中是否有匹配
                if(dp[start] && set.contains(s.substring(start,len))) {
                    dp[len] = true;
                    break;
                }
            }
        }

        return dp[s.length()];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值