(算法题)Day-20230304

电话号码的字母组合

17. 电话号码的字母组合 - 力扣(Leetcode)

思路:1. 回溯,2. 队列

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits: return []

        phone = {'2':['a','b','c'],
                 '3':['d','e','f'],
                 '4':['g','h','i'],
                 '5':['j','k','l'],
                 '6':['m','n','o'],
                 '7':['p','q','r','s'],
                 '8':['t','u','v'],
                 '9':['w','x','y','z']}
                
        def backtrack(conbination,nextdigit):
            if len(nextdigit) == 0:
                res.append(conbination)
            else:
                for letter in phone[nextdigit[0]]:
                    backtrack(conbination + letter,nextdigit[1:])

        res = []
        backtrack('',digits)
        return res
class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits: return []
        phone = ['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
        queue = ['']  # 初始化队列
        for digit in digits:
            for _ in range(len(queue)):
                tmp = queue.pop(0)
                for letter in phone[ord(digit)-50]:# 这里我们不使用 int() 转换字符串,使用ASCII码
                    queue.append(tmp + letter)
        return queue

括号生成

思路回溯法,添加括号的条件:如果左括号数量不大于 \(n\),可以放一个左括号;先放左括号,然后如果右括号数量小于左括号的数量,可以放一个右括号,这样就能保证左右闭合

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> ans = new ArrayList<String>();
        backtrack(ans, new StringBuilder(), 0, 0, n);
        return ans;
    }

    public void backtrack(List<String> ans, StringBuilder cur, int open, int close, int max) {
        if (cur.length() == max * 2) {
            ans.add(cur.toString());
            return;
        }
        if (open < max) {
            cur.append('(');
            backtrack(ans, cur, open + 1, close, max);
            cur.deleteCharAt(cur.length() - 1);
        }
        if (close < open) {
            cur.append(')');
            backtrack(ans, cur, open, close + 1, max);
            cur.deleteCharAt(cur.length() - 1);
        }
    }
}

数组中的第K个最大元素

import java.util.Comparator;
import java.util.PriorityQueue;

public class Solution {

    public int findKthLargest(int[] nums, int k) {
        int len = nums.length;
        // 使用一个含有 k 个元素的最小堆,PriorityQueue 底层是动态数组,为了防止数组扩容产生消耗,可以先指定数组的长度
        PriorityQueue<Integer> minHeap = new PriorityQueue<>(k, Comparator.comparingInt(a -> a));
        // Java 里没有 heapify ,因此我们逐个将前 k 个元素添加到 minHeap 里
        for (int i = 0; i < k; i++) {
            minHeap.offer(nums[i]);
        }

        for (int i = k; i < len; i++) {
            // 看一眼,不拿出,因为有可能没有必要替换
            Integer topElement = minHeap.peek();
            // 只要当前遍历的元素比堆顶元素大,堆顶弹出,遍历的元素进去
            if (nums[i] > topElement) {
                // Java 没有 replace(),所以得先 poll() 出来,然后再放回去
                minHeap.poll();
                minHeap.offer(nums[i]);
            }
        }
        return minHeap.peek();
    }
}

【排序算法之堆排序】

Java PriorityQueue(优先队列)


乘积最大子数组

152. 乘积最大子数组 - 力扣(Leetcode)

思路:动态规划,

遍历数组时计算 当前最大值,不断更新

由于存在负数,那么会导致最大的变最小的,最小的变最大的,因此还需要维护当前最小值 imin

package hhh.hotop100;

/**
 * @author hdbing
 * 乘积最大子序列
 * @create 2023-03-04 13:06
 */
public class T152 {
	public static void main(String[] args) {
		int[] nums = {-2, 2, 4};
		System.out.println(maxProduct(nums));
	}

	static int maxProduct(int[] nums) {
		int max = Integer.MIN_VALUE, imax = 1, imin = 1;
		for (int i = 0; i < nums.length; i++) {
			if (nums[i] < 0) {
				int tmp = imax;
				imax = imin;
				imin = tmp;
			}
			// 通过比较已有的最大值和当前值其实就已经考虑到了 子数组不连续的情况
			// 即到了当前位置当前值较大,只需利用当前值继续迭代即可
			imax = Math.max(imax * nums[i], nums[i]);
			// 由于存在负数,那么会导致最大的变最小的,最小的变最大的,因此还需要维护当前最小值imin
			imin = Math.min(imin * nums[i], nums[i]);

			max = Math.max(max, imax);
		}
		return max;
	}
}

回文子串

思路:找到回文中心后向外扩展,注回文中心有 1或2 两种情况

package hhh.hotop100;

/**
 * @author hdbing
 * @create 2023-03-04 14:55
 */
public class T647 {
	public static void main(String[] args) {
		System.out.println(countSubstrings("abbacc"));
	}

	static int countSubstrings(String s) {
		int num = 0;
		int n = s.length();
		for (int i = 0; i < n; i++)		// 遍历回文中心点
		{
			for (int j = 0; j <= 1; j++)	// j=0,中心是一个点; j=1,中心是两个点
			{
				int l = i;
				int r = i + j;
				while (l >= 0 && r < n && s.charAt(l--) == s.charAt(r++)) {
					num++;
				}
			}
		}
		return num;
	}
}

每日温度

739. 每日温度 - 力扣(Leetcode)

思路:利用一个 递减栈,比栈顶元素小则入栈,反之,则利用下标之差得到结果

 public int[] dailyTemperatures(int[] T) {
        Stack<Integer> stack = new Stack<>();
        int length = T.length;
        int[] result = new int[length];

        for (int i = 0; i < length; i++) {
            while (!stack.isEmpty() && T[i] > T[stack.peek()]) {
                int pre = stack.pop();
                result[pre] = i - pre;  // 注意这里下标应该是 pre
            }
            stack.add(i);  // 栈内保存下标
        }
        return result;
    }

两个链表的第一个公共节点

思路:错的人一定会错过,对的人终究会重逢

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode pA = headA, pB = headB;
        while (pA != pB) {
            pA = pA == null ? headB : pA.next;
            pB = pB == null ? headA : pB.next;
        }
        return pA;
    }
}

回文链表

思路:递归,利用递归 函数栈的特性,将正向遍历的指针放在调用栈之外,这样就能从正向和反向同时进行遍历,从而判断是否是回文链表

class Solution {
    public boolean isPalindrome(ListNode head) {
        List<Integer> vals = new ArrayList<Integer>();

        // 将链表的值复制到数组中
        ListNode currentNode = head;
        while (currentNode != null) {
            vals.add(currentNode.val);
            currentNode = currentNode.next;
        }

        // 使用双指针判断是否回文
        int front = 0;
        int back = vals.size() - 1;
        while (front < back) {
            if (!vals.get(front).equals(vals.get(back))) {
                return false;
            }
            front++;
            back--;
        }
        return true;
    }
}
posted @ 2023-03-05 14:06  黄一洋  阅读(3)  评论(0)    收藏  举报