额外题目练习

leetcode 2 两数相加

注意:需要额外定义一个指针cur,使其让上一个节点的next指向当前节点,这样便能够将单链表相连。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode cur1 = l1;
        ListNode cur2 = l2;
        ListNode cur = null;
        ListNode head = null;
        int temp = 0;//表示进位
        while(cur1 != null || cur2 != null){
            if(cur1 != null && cur2 != null && cur1.val + cur2.val + temp >= 10){
                if(cur == null){
                    head = new ListNode(cur1.val + cur2.val - 10 + temp);
                }
                if(cur != null){
                    ListNode node = new ListNode(cur1.val + cur2.val - 10 + temp);
                    temp = 1;
                    cur.next = node;
                    cur = node;
                    cur1 = cur1.next;
                    cur2 = cur2.next;
                    continue;
                }
                temp = 1;
                cur = head;
            }else if(cur1 != null && cur2 != null){
                if(cur == null){
                    head = new ListNode(cur1.val + cur2.val + temp);
                }
                if(cur != null){
                    ListNode node = new ListNode(cur1.val + cur2.val + temp);
                    temp = 0;
                    cur.next = node;
                    cur = node;
                    cur1 = cur1.next;
                    cur2 = cur2.next;
                    continue;
                }
                temp = 0;
                cur = head;
            }else if(cur1 == null){
                if(cur2.val + temp >= 10){
                    ListNode node = new ListNode(cur2.val + temp - 10);
                    temp = 1;
                    cur.next = node;
                    cur = node;
                    cur2 = cur2.next;
                    continue;

                }else{
                    ListNode node = new ListNode(cur2.val + temp);
                    temp = 0;
                    cur.next = node;
                    cur = node;
                    cur2 = cur2.next;
                    continue;
                }
            }else{
                if(cur1.val + temp >= 10){
                    ListNode node = new ListNode(cur1.val + temp - 10);
                    temp = 1;
                    cur.next = node;
                    cur = node;
                    cur1 = cur1.next;
                    continue;

                }else{
                    ListNode node = new ListNode(cur1.val + temp);
                    temp = 0;
                    cur.next = node;
                    cur = node;
                    cur1 = cur1.next;
                    continue;
                }

            }
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        if(temp == 1){
            ListNode node = new ListNode(1);
            cur.next = node;
        }
        return head;
    }
}

leetcode 283 移动零

本题注意双指针的应用

    public void moveZeroes(int[] nums) {
        //使用双指针:前面的指针遇见非0且后面的指针是0,则将后面指针的值赋给前面指针
        int i = 0;
        int j = 1;
        while(j < nums.length){
            if(nums[i] == 0 && nums[j] != 0){
                nums[i] = nums[j];
                nums[j] = 0;
                i++;
                j++;
                continue;
            }
            if(nums[i] != 0 && nums[j] == 0){
                i++;
                j++;
                continue;
            }
            if(nums[i] ==0 && nums[j] ==0){
                j++;
                continue;
            }
            if(nums[i] != 0 && nums[j] != 0){
                i++;
                j++;
                continue;
            }
        }

    }
}

leetcode 1365 有多少小于当前数字的数字

    public int[] smallerNumbersThanCurrent(int[] nums) {
        int[] res = new int[nums.length];
        //定义两层for循环
        for(int i = 0; i < nums.length; i++){
            for(int j = 0; j < nums.length; j++){
                if(nums[j] < nums[i]){
                    res[i]++;
                }
            }
        }
        return res;
    }
}

leetcode 941 有效的山脉数组

    public boolean validMountainArray(int[] arr) {
        if(arr.length < 3){
            return false;
        }
        int max = arr[0];
        int flag = 0;
        for(int i = 1; i < arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
                flag = i;
            }
            if(arr[i] == arr[i - 1]){
                return false;
            }
        }
        if(flag == arr.length - 1 || flag == 0){
            return false;
        } 
        //定义双指针
        int i = 0;
        int j = arr.length - 1;
        while(i < flag || j > flag){
            if(i < flag && arr[i + 1] > arr[i]){
                i++;
            }
            if(i < flag && arr[i + 1] < arr[i]){
                return false;
            }
            if(j > flag && arr[j - 1] > arr[j]){
                j--;
            }
            if(j > flag && arr[j - 1] < arr[j]){
                return false;
            }
        }
        return true;
    }
}

leetcode 1207 独一无二的出现次数

本题使用了HashMap和HashSet。注意相关API的调用

    public boolean uniqueOccurrences(int[] arr) {
        //定义hashMap
        HashMap<Integer, Integer> map = new HashMap<>();
        //遍历数组,值作为键,出现次数作为值
        for(int i = 0; i < arr.length; i++){
            //多次出现
            if(map.containsKey(arr[i])){
                map.put(arr[i], map.get(arr[i]) + 1);
            }else{
                //第一次出现
                map.put(arr[i], 1);
            }
        }
        //定义hashset
        HashSet<Integer> set = new HashSet<>();
        for(int value : map.values()){
            if(set.contains(value)){
                return false;
            }else{
                set.add(value);
            }
        }
        return true;
    }
}

leetcode 189 轮转数组

解法1:空间复杂度为O(n),需要重新开辟数组存储结果。

    public int[] rotate(int[] nums, int k) {
        //定义存放结果的数组
        int[] res = new int[nums.length];
        for(int i = 0; i < nums.length; i++){
            //若原始的下标加上k小于最大下标,则直接赋值到对应位置
            if(i + k < nums.length){
                res[i + k] = nums[i];
            }
            //否则,对下标取模
            if(i + k >= nums.length){
                res[(i + k) % nums.length] = nums[i];
            }
        }
        return res;
    }
}

解法2:在原数组上修改,空间复杂度为O(1)。

    public void reverse(int[] nums, int i, int j){
        int temp;
        while(i < j){
            temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            i++;
            j--;
        }
    }
    public void rotate(int[] nums, int k) {
        //处理k大于nums的长度的情况
        k = k % nums.length;
        //先将整个nums翻转
        reverse(nums, 0, nums.length - 1);
        //再翻转前k个元素
        reverse(nums, 0, k - 1);
        //再翻转后k个元素
        reverse(nums, k, nums.length - 1);
    }
}

leetcode724 寻找数组的中心下标

class Solution {
public int pivotIndex(int[] nums) {
for(int i = 0; i < nums.length; i++){
//注意每次循环都要将sumLeft与sumRight置于0
int sumLeft = 0;
int sumRight = 0;
for(int j = 0; j < i; j++){
sumLeft += nums[j];
}
for(int k = i + 1; k < nums.length; k++){
sumRight += nums[k];
}
if(sumLeft == sumRight){
return i;
}
}
return -1;
}
}

leetcode 34 在排序数组中查找元素的第一个和最后一个位置

注意:利用二分查找以及循环不变量(区间左闭右闭)的思想。

    //寻找target的左边界
    public int leftBorder(int[] nums, int target){
        int left = 0;
        int right = nums.length - 1;
        int leftBorder = -2;
        //注意循环不变量:区间都是左闭右闭
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid - 1;
                leftBorder = right;
            }
        }
        return leftBorder;
    }
    //寻找target的有右边界
    public int rightBorder(int[] nums, int target){
        int left = 0;
        int right = nums.length - 1;
        int rightBorder = -2;
        //注意循环不变量:区间都是左闭右闭
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] > target){
                right = mid - 1;

            }else{
               left = mid + 1;
               rightBorder = left;
            }
        }
        return rightBorder;
    }
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[2];
        Arrays.fill(res, -1);
        if(nums.length == 0){
            return res;
        }
        int leftBorder = leftBorder(nums, target);
        int rightBorder = rightBorder(nums,target);
        if(leftBorder == -2 || rightBorder == -2){
            return res;
        }else if(rightBorder - leftBorder >= 2){
            res[0] = leftBorder + 1;
            res[1] = rightBorder - 1;
            return res;
        }else{
            return res;
        }
       
    }
}

leetcode 922 按奇偶排序数组(2)

注意:本题中将不符合规则的元素交换一次,则会有两个位置的元素符合规则。

    public int[] sortArrayByParityII(int[] nums) {
        for(int i = 0; i < nums.length; i++){
            if(i % 2 == 0 && nums[i] % 2 == 0){
                continue;
            }
            if(i % 2 == 0 && nums[i] % 2 != 0){
                int temp = nums[i];
                //找到下一个i是奇数但nums[i]是偶数的位置
                for(int j = i + 1; j < nums.length; j++){
                    if(j % 2 == 1 && nums[j] % 2 == 0){
                        nums[i] = nums[j];
                        nums[j] = temp;
                        break;
                    }
                }
            }
            if(i % 2 == 1 && nums[i] % 2 == 1){
                continue;
            }
            if(i % 2 == 1 && nums[i] % 2 == 0){
                int temp2 = nums[i];
                //找到以一个i是偶数但nums[i]是奇数的位置
                for(int j = i + 1; j < nums.length; j++){
                    if(j % 2 == 0 && nums[j] % 2 == 1){
                        nums[i] = nums[j];
                        nums[j] = temp2;
                        break;
                    }
                }
            }
        }
        return nums;
    }
}

leetcode 35 搜索插入位置

    public int searchInsert(int[] nums, int target) {
        if(target < nums[0]){
            return 0;
        }
        if(target > nums[nums.length - 1]){
            return nums.length;
        }
        //采用二分查找,注意使用循环不变量
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] < target){
                left = mid + 1;
            }else if(nums[mid] > target){
                right = mid - 1;
            }else{
                return mid;
            }
        }
        //说明target应该插入到数组的内部
        return left;
    }
}

leetcode 234 回文链表

本题我借助了翻转链表来判断回文

 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    //翻转链表
    public ListNode traverse(ListNode head){
        //定义虚拟头节点
        ListNode dummy = new ListNode(-1, null);
        ListNode cur = head;
        ListNode pre = dummy;
        ListNode temp = null;
        while(cur != null){
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        dummy = null;
        return pre;
    }
    public boolean isPalindrome(ListNode head) {
        List<Integer> list = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        ListNode cur = head;
        while(cur != null){
            list.add(cur.val);
            cur = cur.next;
        }
        //翻转链表
        ListNode head1 = traverse(head);
        cur = head1;
        while(cur != null){
            list2.add(cur.val);
            cur = cur.next;
        }
        //比较list1与list2中的值是否相等
        for(int i = 0; i < list.size(); i++){
            if(list.get(i) != list2.get(i)){
                return false;
            }
        }
        return true;
    }
}

leetcode 143 重排链表

 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public void reorderList(ListNode head) {
        //利用双端队列辅助进行链表的重排
        Deque<Integer> dq = new LinkedList<>();
        ListNode cur = head.next;
        while(cur != null){
            dq.add(cur.val);
            cur = cur.next;
        }
        //再一前一后的将元素出队,并将其连成链表
        ListNode pre = head;
        while(dq.size() != 0){
            ListNode node = new ListNode(dq.pollLast(), null);
            pre.next = node;
            pre = node;
            if(dq.size() != 0){
                ListNode node2 = new ListNode(dq.pollFirst(), null);
                pre.next = node2;
                pre = node2;
            }
        }
    }
}

leetcode1002 查找共用字符

注意:ASCii码转字符的方法:用强制类型转换(char)(i + ‘a’);
字符转字符串的方法:String.valueOf(char);

    public List<String> commonChars(String[] words) {
       List<String> res = new ArrayList<>();
       int[] count = new int[26];//用于存放所有单词比较之后,不为0的位置对应字母的出现次数
       for(int i = 0; i < words[0].length(); i++){
          count[words[0].charAt(i) - 'a']++;//计算第一个单词每个字母出现的次数
       }
       for(int i = 1; i < words.length; i++){
           int[] others = new int[26];
           for(int j = 0; j < words[i].length(); j++){
                others[words[i].charAt(j) - 'a']++;
           }
           for(int k = 0; k < count.length; k++){
               count[k] = Math.min(count[k], others[k]);
           }
       }
       for(int i = 0; i < count.length; i++){
           if(count[i] != 0){
               int temp = count[i];
               while(temp > 0){
                   char temp2 = (char)(i + 'a');
                   res.add(String.valueOf(temp2));
                   temp--;
               }
           }
       }
       return res;
    }
}

leetcode 925 长按键入

    public boolean isLongPressedName(String name, String typed) {
        char[] name1 = name.toCharArray();
        char[] typed1 = typed.toCharArray();
        if(name1.length > typed1.length){
            return false;
        }
        int i = 0, j = 0;
        while(i < name1.length && j < typed1.length){
            if(name1[i] == typed1[j]){
                i++;
                j++;
            }else{
                if(j == 0){
                    return false;//第一个字母就不相等
                }
                while(j < typed1.length - 1 && typed1[j] == typed1[j - 1]){
                    j++;//让typed跳过相同的字母
                }
                if(name1[i] == typed1[j]){
                    i++;
                    j++;
                }else{
                    return false;//typed跳过重复的字母后,第一个新的字母便不匹配
                }
            }
        }
        if(i < name1.length){
            return false;//说明name1还没匹配完
        }
        if(j < typed1.length){
            while(j < typed1.length && typed1[j] == typed1[j - 1]){
                j++;
            }
        }
        if(j < typed1.length){
            return false;
        }else{
            return true;
        }
    }
}

leetcode 844 比较含退格的字符串

本题涉及关键字“匹配”“消除”,所以一定考虑用栈来解决。

    public boolean backspaceCompare(String s, String t) {
        //本题使用栈
        //定义string当作栈使用
        String s_t = "";
        String t_t = "";
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) != '#'){
                s_t += s.charAt(i);
            }else{
                if(s_t.length() != 0){
                    s_t = s_t.substring(0, s_t.length() - 1);
                }
            }
        }
        for(int i = 0; i < t.length(); i++){
            if(t.charAt(i) != '#'){
                t_t += t.charAt(i);
            }else{
                if(t_t.length() != 0){
                    t_t = t_t.substring(0, t_t.length() - 1);
                }
            }
        }
        //判断结果
        if(s_t.equals(t_t)){
            return true;
        }else{
            return false;
        }
    }
}

利用栈:

    public boolean backspaceCompare(String s, String t) {
        //本题使用栈
       Stack<Character> st = new Stack<>();
       Stack<Character> st2 = new Stack<>();
       for(int i = 0; i < s.length(); i++){
           if(s.charAt(i) != '#'){
               st.push(s.charAt(i));
           }else{
               if(!st.isEmpty()){
                   st.pop();
               }
           }
        }
        for(int i = 0; i < t.length(); i++){
            if(t.charAt(i) != '#'){
                st2.push(t.charAt(i));
            }else{
                if(!st2.isEmpty()){
                    st2.pop();
                }
            }
        }
        //判断结果
        if(st.size() != st2.size()){
            return false;
        }
        while(!st.isEmpty() && !st2.isEmpty()){
            if(st.pop() == st2.pop()){
                continue;
            }else{
                return false;
            }
        }
        return true;
    }
}

常用的工具

1.HashMap根据value获取key

     * 根据value获取所有key
     */
    private static Set<String> getKeys(Map<String,String> map, String value){
        Set<String> keySet = new HashSet<>();
        // 遍历map
        for (Map.Entry<String, String> entry : map.entrySet()) {
            // 如果value和key对应的value相同
            if(value.equals(entry.getValue())){
                keySet.add(entry.getKey());
            }
        }
        return keySet;
    }

2.比较大小
a, b分别是长度为2的数组
Arrays.sort(数组名, (a, b)-> {
return a[0] - b[0];//升序
})
3.优先队列,自定义大根堆(需要实现比较器(Comparator)接口)
方法1:lambda表达式

PriorityQueue<Integer> queue = new PriorityQueue<>(
                (o1, o2) -> o2 - o1
        );

方法2:重写compare方法

		PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

leetcode 129 求根节点到叶子节点数字之和

本题需要使用递归三步曲。

 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> res = new ArrayList<>();
    public void traverse(TreeNode root, String s){
        //递归退出的条件
        if(root.left == null && root.right == null){
            s += String.valueOf(root.val);
            res.add(Integer.valueOf(s));
            return;
        }
        //处理单层递归逻辑
        s += String.valueOf(root.val);
        if(root.left != null){
            traverse(root.left, s);
        }
        if(root.right != null){
            traverse(root.right, s);
        }
        return;
    }
    public int sumNumbers(TreeNode root) {
        int sum = 0;
        traverse(root, "");
        for(int i = 0; i < res.size(); i++){
            sum += res.get(i);
        }
        return sum;

    }
}

leetcode 1382 将二叉搜索树变平衡

见到BST,首先考虑中序遍历。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> temp = new ArrayList<>();
    public void inorder(TreeNode root){
        if(root == null){
            return;
        }
        if(root.left != null){
            inorder(root.left);
        }
        temp.add(root.val);
        if(root.right != null){
            inorder(root.right);
        }
    }
    public TreeNode build(int low, int high){
        if(high < low){
            return null;
        }
        int mid = (low + high) / 2;
        TreeNode node = new TreeNode(temp.get(mid));
        node.left = build(low, mid - 1);
        node.right = build(mid + 1, high);
        return node;
    }
    public TreeNode balanceBST(TreeNode root) {
        inorder(root);
        return build(0, temp.size() - 1);
    }
}

leetcode 100 相同的树

补充:层序遍历

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(queue.size() != 0){
            TreeNode temp = queue.poll();
            res.add(temp.val);
            if(temp.left != null){
                queue.offer(temp.left);
            }
            if(temp.right != null){
                queue.offer(temp.right);
            }
        }
    }

利用递归三步曲:

 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p == null && q == null){
            return true;
        }
        else if(p == null && q != null){
            return false;
        }
        else if(p != null && q == null){
            return false;
        }
        else{
            if(p.val != q.val){
                return false;
            }
            else{
                boolean leftSame = isSameTree(p.left, q.left);
                boolean rightSame = isSameTree(p.right, q.right);
                if(leftSame == true && rightSame == true){
                    return true;
                }else{
                    return false;
                }
            }
        }
    }
}

leetcode 116 填充每一个节点的下一个节点的右侧指针

注意:在考虑单层递归逻辑的时候,要覆盖整颗树中所能遇见的全部情况。

// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    private void connectHelper(Node root){
        if(root == null){
            return;
        }
        if(root.left != null){
            root.left.next = root.right;
        }
        if(root.right != null){
            if(root.next != null){
                root.right.next = root.next.left;
            }
        }
        connectHelper(root.left);
        connectHelper(root.right);
    }
    public Node connect(Node root) {
        connectHelper(root);
        return root;
    }
}

leetcode 841 钥匙和房间

本题属于有向图搜索全路径的问题。 只能用深搜(DFS)或者广搜(BFS)来搜。
注意:若在递归函数中需要保留每一层递归中对变量修改后的状态,则需要将该变量作为递归函数的参数传入。

    private void dfs(List<List<Integer>> rooms, int key, boolean[] visited){
        //采用深度优先搜索
        if(visited[key] == true){
            return;//说明该房间被访问过了
        }
        visited[key] = true;
        List<Integer> keys = rooms.get(key);
        for(int key1 : keys){
            dfs(rooms, key1, visited);
        }

    }
    public boolean canVisitAllRooms(List<List<Integer>> rooms) {
        boolean[] visited = new boolean[rooms.size()];
        dfs(rooms, 0, visited);
        for(boolean vis : visited){
            if(vis == false){
                return false;
            }
        }
        return true;

    }
}

leetcode 797 所有可能的路径

class Solution {
    private List<List<Integer>> res;
    private List<Integer> path ;
    private void dfs(int[][] graph, int node){
        if(node == graph.length - 1){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i = 0; i < graph[node].length; i++){
            path.add(graph[node][i]);
            dfs(graph, graph[node][i]);
            path.remove(path.size() - 1);
        }
    }
    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        res = new ArrayList<>();
        path = new ArrayList<>();
        path.add(0);
        dfs(graph, 0);
        return res;
 
    }
}

leetcode127 单词接龙

本题首先将只相差一个字符的单词想连接,构成无向图;再利用广度优先搜索求无向图的最短路径。
因为广搜只要到达终点则一定是最短路径。
注意:map容器添加元素是put()方法。根据键获取值是get()方法。字符数组转换成字符串可以用String.valueOf()。替换字符串中的字母可以先将字符串转换成字符数组。ASCii强制类型转换成字符用(char)。
广搜要借助队列。队列的定义为
Queue queue = new LinkedList<>();

    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        //将wordList中的单词存放如set中
        HashSet<String> set = new HashSet<>();
        for(int i = 0; i < wordList.size(); i++){
            set.add(wordList.get(i));
        }
        //定义map存放访问过的元素以及访问过的路径的长度
        HashMap<String, Integer> map = new HashMap<>();
        //若endWord不在wordList中,直接返回0
        if(!set.contains(endWord)){
            return 0;
        } 
        //将beginWord加入map
        map.put(beginWord, 1);
        //定义队列存放上一个访问的元素
        Queue<String> queue = new LinkedList<>();
        queue.offer(beginWord); //定义队列,进行广度遍历
        while(!queue.isEmpty()){
            //遍历set,找到与前一个访问元素只相差一个字符的元素连接成路径中的一个节点
            String newWord = queue.poll();
            for(int i = 0; i < newWord.length(); i++){
                for(int j = 0; j < 26; j++){
                    char[] temp = newWord.toCharArray();
                    temp[i] = (char)(j + 'a');
                    String newWord2 = String.valueOf(temp);
                    if(newWord2.equals(endWord)){
                        return map.get(newWord) + 1;
                    }
                    if(set.contains(newWord2) && !map.containsKey(newWord2)){
                        map.put(newWord2, map.get(newWord) + 1);
                        queue.offer(newWord2);
                    }
                }
            }
        }
        return 0;//没有找到
        
    }
}

leetcode 684 冗余连接

本题属于并查集的应用。
并查集主要用于解决集合问题,两个节点在不在一个集合,也可以将两个节点添加到一个集合中

并查集主要有3个功能
1.寻找根节点,函数:find(int u),也就是判断这个节点的祖先节点是哪个;
2.将两个节点接入到同一个集合,函数:join(int u, int v),将两个节点连在同一个根节点上;
3.判断两个节点是否在同一个集合,函数:isSame(int u, int v),就是判断两个节点是不是同一个根节点。

    //本题需要使用并查集
    public int[] father;
    public int find(int u){
        if(u == father[u]){
            return u;
        }else{
            father[u] = find(father[u]);
            return father[u];
        }
    }
    private void join(int u, int v) {
        u = find(u);
        v = find(v);
        if (u == v) return ;
        father[v] = u;
    }
    
    public int[] findRedundantConnection(int[][] edges) {
        father = new int[1005];
        //初始化并查集
        for(int i = 0; i < 1005; i++){
            father[i] = i;
        }
        //不断连接edges中的边
        for(int i = 0; i < edges.length; i++){
            if(find(edges[i][0]) == find(edges[i][1])){
                return edges[i];
            }
            else{
               join(edges[i][0], edges[i][1]);
            }
        }
        return null;
    }
}

leetcode 685 冗余连接(2)

如果两个点所在的边在添加图之前如果就可以在并查集里找到了相同的根,那么这条边添加上之后这个图一定不是树了。

class Solution {
    public int[] father;
    public int find(int u){
        if(u == father[u]){
            return u;
        }else{
            father[u] = find(father[u]);
            return father[u];
        }
    }
    public void join(int u, int v){
        u = find(u);
        v = find(v);
        if(u == v) return;
        father[v] = u;
    }
    public boolean isSame(int u, int v){
        u = find(u);
        v = find(v);
        return u == v;
    }
    public void initFather(){
        father = new int[1005];
        for(int i = 0; i < 1005; i++){
            father[i] = i;
        }
    }
    //其实就是判断去除一条边之后,剩下的边是否还会构成环
    public boolean isTreeAfterRemove(int[][] edges, int[] removeEdge){
        initFather();
        for(int i = 0; i < edges.length; i++){
            if(edges[i][0] == removeEdge[0] && edges[i][1] == removeEdge[1]){
                continue;
            }
            if(isSame(edges[i][0], edges[i][1])){
                return false;
            }
            join(edges[i][0], edges[i][1]);
        }
        return true;
    }
    public int[] findRedundantDirectedConnection(int[][] edges) {
        //先找是否存在入度为2的节点
        int[] inDegree = new int[edges.length + 1];
        for(int i = 0; i < edges.length; i++){
            inDegree[edges[i][1]] += 1;
        }
        List<int[]> temp = new ArrayList<>();
        for(int i = 0; i < inDegree.length; i++){
            if(inDegree[i] == 2){
                for(int j = edges.length - 1; j >= 0; j--){
                    if(edges[j][1] == i){
                        temp.add(edges[j]);
                    }
                }
            }
        }
        if(!temp.isEmpty()){
            if(isTreeAfterRemove(edges, temp.get(0))){
                return temp.get(0);
            }else{
                return temp.get(1);
            }
        }
        //若图中没有入度为2的节点,则一定存在环,此时利用并查集
        initFather();
        for(int i = 0; i < edges.length; i++){
            if(isSame(edges[i][0], edges[i][1])){
                return edges[i];
            }
            join(edges[i][0], edges[i][1]);
        }
        return null;
    }
}

leetcode 1356 根据数字二进制下1的数目排序

解法1:(暴力)

    public List<Integer> binary = new ArrayList<>();
    public void transToBinary(int num){
        while(num / 2 != 0){
            binary.add(num % 2);
            num = num / 2;
        }
    }
    public int count1(List<Integer> list){
        int counts_1 = 0;
        for(int i = 0; i < list.size(); i++){
            if(list.get(i) == 1){
                counts_1++;
            }
        }
        return counts_1;
    }
    public int[] sortByBits(int[] arr) {
        for(int i = 0; i < arr.length - 1; i++){
            for(int j = i + 1; j < arr.length; j++){
                transToBinary(arr[i]);
                int temp = count1(binary);
                binary = new ArrayList<>();
                transToBinary(arr[j]);
                int temp2 = count1(binary);
                binary = new ArrayList<>();
                int temp3 = 0;
                if(temp2 < temp){
                    temp3 = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp3;
                }
                if(temp2 == temp){
                    if(arr[j] < arr[i]){
                        temp3 = arr[j];
                        arr[j] = arr[i];
                        arr[i] = temp3;
                    }
                }
            }
        }
        return arr;
    }
}

leetcode 463 岛屿的周长

    public int islandPerimeter(int[][] grid) {
        int sum = 0;//记录岛屿的数量
        int cover = 0;//记录相邻岛屿的数量
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j < grid[0].length; j++){
                if(grid[i][j] == 1){
                    sum++;
                    //与上边的岛屿相邻
                    if(i - 1 >= 0 && grid[i - 1][j] == 1){
                        cover++;
                    }
                    //与左边岛屿相邻
                    if(j - 1 >= 0 && grid[i][j - 1] == 1){
                        cover++;
                    }
                }
            }
        }
        return sum * 4 - cover * 2;
    }
}

leetcode 31 下一个排列

    public void nextPermutation(int[] nums) {
        for(int i = nums.length - 1; i >= 0; i--){
            for(int j = nums.length - 1; j > i; j--){
                if(nums[j] > nums[i]){
                    int temp = nums[j];
                    nums[j] = nums[i];
                    nums[i] = temp; 
                    Arrays.sort(nums, i + 1, nums.length);
                    return;
                }
            }
        }
        Arrays.sort(nums);
    }
}

leetcode 657 机器人能否返回原点

    public boolean judgeCircle(String moves) {
        char[] move = moves.toCharArray();
        int flag_R = 0, flag_L = 0, flag_U = 0, flag_D = 0;
        int flag = 0;
        for(int i = 0; i < move.length; i++){
            if(move[i] == 'R'){
                flag_R++;
            }
            if(move[i] == 'L'){
                flag_L--;
            }
            if(move[i] == 'U'){
                flag_U++;
            }
            if(move[i] == 'D'){
                flag_D++;
            }
            if(move[i] == 'R' || move[i] == 'U'){
                flag++;
            }
            if(move[i] == 'L' || move[i] == 'D'){
                flag--;
            }
        }
        if(flag_R == flag_L && flag_D == flag_U){
            return true;
        }else if(flag == 0 && flag_L == 0 && flag_U == 0){
            return false;
        }else if(flag == 0 && flag_D == 0 && flag_R == 0){
            return false;
        }else if(flag == 0){
            return true;
        }else{
            return false;
        }
    }
}

leetcode 5 最长回文子串

    public String longestPalindrome(String s) {
        String res = "";
        int left = 0, right = 0;
        int maxLength = 0;
        //定义dp数组,下标i和j表示左闭右闭区间对应的字符串是否为回文
        boolean[][] dp = new boolean[s.length()][s.length()];
        //定义遍历顺序:从下往上,从左到右(根据dp数组的定义,j一定是大于等于i的)
        for(int i = s.length() - 1; i >= 0; i--){
            for(int j = i; j < s.length(); j++){
                if(s.charAt(i) == s.charAt(j)){
                    if(j - i <= 1){
                        dp[i][j] = true;
                    }else if(j - i > 1 && dp[i + 1][j - 1]){
                        dp[i][j] = true;
                    }
                }
                if(dp[i][j] && j - i + 1 > maxLength){
                    maxLength = j - i + 1;
                    left = i;
                    right = j;
                }
            }
        }
        for(int i = left; i <= right; i++){
            res += s.charAt(i);
        }
        return res;
    }
}

leetcode 132 分割回文串(2)

class Solution {
    public int minCut(String s) {
        boolean[][] isPanlindrome = new boolean[s.length()][s.length()];
        for(int i = s.length() - 1; i >= 0; i--){
            for(int j = i; j < s.length(); j++){
                if(s.charAt(i) == s.charAt(j) && (j - i <= 1 || isPanlindrome[i + 1][j - 1])){
                    isPanlindrome[i][j] = true;
                }
            }
        }
        int[] dp = new int[s.length()];
        dp[0] = 0;
        for(int i = 1; i < s.length(); i++){
            dp[i] = i;
        }
        for(int i = 1; i < s.length(); i++){
            if(isPanlindrome[0][i]){
                dp[i] = 0;
                continue;
            }
            for(int j = 0; j < i; j++){
                if(isPanlindrome[j + 1][i]){
                    dp[i] = Math.min(dp[i], dp[j] + 1);
                }
            }
        }
        return dp[s.length() - 1];
    }
}

leetcode 673 最长递增子序列的个数

class Solution {
    public int findNumberOfLIS(int[] nums) {
        int maxCount = 0;
        int res = 0;
        //特判
        if(nums.length == 1){
            return 1;
        }
        //定义数组dp,dp[i]表示最长递增子序列的长度,初始化为1
        int[] dp = new int[nums.length];
        Arrays.fill(dp, 1);
        //定义数组count,count[i]表示以nums[i]为结尾的数组所包含的最长递增子序列的个数
        int[] count = new int[nums.length];
        Arrays.fill(count, 1);
        for(int i = 1; i < nums.length; i++){
            for(int j = 0; j < i; j++){
                if(nums[i] > nums[j]){
                    if(dp[j] + 1 > dp[i]){
                        count[i] = count[j];
                    }else if(dp[j] + 1 == dp[i]){
                        count[i] += count[j];
                    }
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
                if(dp[i] > maxCount){
                    maxCount = dp[i];
                }
            }
        }
        for(int i = 0; i < dp.length; i++){
            if(dp[i] == maxCount){
                res += count[i];
            }
        }
        return res;
    }
}

leetcode 649 Dota2参议院

以下解法在力扣中运行超时。

class Solution {
    public String predictPartyVictory(String senate) {
        //本题使用贪心的策略,尽量去消灭后面的对手,因为前面的对手已经用过其权力了,而后面的对手还会利用权力消灭自己的队友
        char[] senate1 = senate.toCharArray();
        int countR = 0;
        int countD = 0;
        while(true){
            for(int i = 0; i < senate1.length; i++){
            if(senate1[i] == 'X'){
                continue;
            }
            if(senate1[i] == 'R' && i < senate1.length - 1){
                for(int j = i + 1; j < senate1.length; j++){
                    if(senate1[j] == 'D'){
                        senate1[j] = 'X';
                        break;
                    }
                }
            }
            if(senate1[i] == 'R' && i == senate1.length - 1){
                for(int j = 0; j < senate1.length - 1; j++){
                    if(senate1[j] == 'D'){
                        senate1[j] = 'X';
                        break;
                    }
                }
            }
            if(senate1[i] == 'D' && i < senate1.length - 1){
                for(int j = i + 1; j < senate1.length; j++){
                    if(senate1[j] == 'R'){
                        senate1[j] = 'X';
                        break;
                    }
                }
            }
            if(senate1[i] == 'D' && i == senate1.length - 1){
                for(int j = 0; j < senate1.length - 1; j++){
                    if(senate1[j] == 'R'){
                        senate1[j] = 'X';
                        break;
                    }
                }
            }
            }
            for(char temp : senate1){
                if(temp == 'R'){
                    countR++;
                }else if(temp == 'D'){
                    countD++;
                }
            }
            if(countD == 0 || countR == 0){
                break;
            }
        }
        if(countD == 0){
            return "Radiant";
        }
        else{
            return "Dire";
        }
    }
}

另外的解法:
注意: String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示

    public String predictPartyVictory(String senate) {
        //本题使用贪心的策略,尽量去消灭后面的对手,因为前面的对手已经用过其权力了,而后面的对手还会利用权力消灭自己的队友
       boolean R = true;
       boolean D = true;
       int flag = 0;//大于0表示R在D前面,则可以消除D;小于0表示R在D后面,则可以消除R。
       byte[] senate1 = senate.getBytes();
       while(R && D){
           R = false;
           D = false;
           for(int i = 0; i < senate1.length; i++){
               if(senate1[i] == 'R'){
                   if(flag < 0){
                       senate1[i] = 0;//说明D在R之前,消灭R
                   }else{
                       R = true;
                    }
                    flag++;
                }
                if(senate1[i] == 'D'){
                    if(flag > 0){
                        senate1[i] = 0;
                    }else{
                        D = true;
                    }
                    flag--;
                }
            }
        }
        return R == true ? "Radiant" : "Dire";
    }
}

leetcode 1221 分割平衡字符串

    public int balancedStringSplit(String s) {
        int countR = 0;
        int countL = 0;
        int res = 0;
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) == 'R'){
               countR++;
            }else if(s.charAt(i) == 'L'){
                countL++;
            }
            if(countL == countR){
                res++;
                countL = 0;
                countR = 0;
            }
        }
        return res;
    }
}

leetcode 52 N皇后(2)

本题利用回溯算法。回溯的变量的棋盘对应矩阵的行row。

class Solution {
    public int res = 0;
    public char[][] board;
    public boolean helper(int row, int col, char[][] board, int n){
        //判断是否为同列
        for(int i = 0; i < row; i++){
            if(board[i][col] == 'Q'){
                return false;
            }
        }
        //判断是否为斜线45°
        for(int i = row - 1, j = col - 1; i >=0 && j >=0; i--,j--){
            if(board[i][j] == 'Q'){
                return false;
            }
        }
        //判断是否为斜线135°
        for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++){
            if(board[i][j] == 'Q'){
                return false;
            }
        }
        return true;
    }
    public void backtracking(int n, int row, char[][] board){

        if(row == n){
            res++;
            return;
        }
        for(int i = 0; i < n; i++){
           
                if(helper(row, i, board, n)){
                    board[row][i] = 'Q';
                    backtracking(n, row + 1, board);
                    board[row][i] = '.';
                } 
            
        }
    }
    public int totalNQueens(int n) {
        board = new char[n][n];
        for(char[] temp : board){
            Arrays.fill(temp, '.');
        }
        backtracking(n, 0, board);
        return res;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值