146、LRU 缓存
class LRUCache {
int capacity;
LinkedHashMap<Integer, Integer> cache;
public LRUCache(int capacity) {
this.capacity = capacity;
cache = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return cache.size() > capacity;
}
};
}
public int get(int key) {
return cache.getOrDefault(key, -1);
}
public void put(int key, int value) {
cache.put(key, value);
}
}
148、排序链表
自顶向下的归并排序。先用快慢指针的方法,找到链表的中间点。然后通过归并排序的思想,分开对两个子链表进行排序,然后合并。
class Solution {
public ListNode sortList(ListNode head) {
if(head==null || head.next==null){
return head;
}
ListNode fast = head;
ListNode slow = head;
ListNode pre = head;
while(fast!=null && fast.next!=null){
pre = slow;
fast = fast.next.next;
slow = slow.next;
}
pre.next = null;
ListNode l1 = sortList(head);
ListNode l2 = sortList(slow);
return sort(l1,l2);
}
ListNode sort(ListNode l1,ListNode l2){
ListNode p = new ListNode();
ListNode l = p;
while(l1!=null && l2!=null){
if(l1.val<l2.val){
p.next = l1;
l1 = l1.next;
} else{
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
if(l1!=null){
p.next = l1;
}
if(l2!=null){
p.next = l2;
}
return l.next;
}
}
152、乘积最大子数组
因为数组中的数有正有负,所以要设立两个值,imax和imin。当数为负数的时候,imax和imin的值互换。真正的最大值max是imax和imin的最大值。
class Solution {
public int maxProduct(int[] nums) {
int max = Integer.MIN_VALUE;
int 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 = Math.min(imin*nums[i],nums[i]);
max = Math.max(max,imax);
}
return max;
}
}
155、最小栈
A为基本栈,B为辅助栈。当B为空或者B的peek值大时,向B入栈。
class MinStack {
Stack<Integer> A,B;
public MinStack() {
A=new Stack<>();
B=new Stack<>();
}
public void push(int val) {
A.add(val);
if(B.empty() || B.peek()>=val){
B.add(val);
}
}
public void pop() {
if(A.pop().equals(B.peek())){
B.pop();
}
}
public int top() {
return A.peek();
}
public int getMin() {
return B.peek();
}
}
160、相交链表
建立一个判断链表节点是否相等的方法。然后操作head1和head2的链表在同一长度起步。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode l1 = headA;
ListNode l2 = headB;
int size1 = 0,size2 = 0;
while(l1!=null){
l1 = l1.next;
size1++;
}
while(l2!=null){
l2 = l2.next;
size2++;
}
if(size1>=size2){
while(size1>size2){
headA = headA.next;
size1--;
}
}
else{
while(size1<size2){
headB = headB.next;
size2--;
}
}
while(headA!=null && headB!=null){
if(headA != headB){
headA = headA.next;
headB = headB.next;
}
else{
if(dis(headA,headB) == true){
return headA;
}
else{
headA = headA.next;
headB = headB.next;
}
}
}
return null;
}
boolean dis(ListNode headA,ListNode headB){
if(headA==null){
return true;
}
if(headA == headB){
return dis(headA.next,headB.next);
}
else{
return false;
}
}
}
169、多数元素
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
int size = nums.length;
for(int i=0;i<size;i++){
if(nums[i] == nums[i+size/2]){
return nums[i];
}
}
return -1;
}
}
198、打家劫舍
动态规划,偷窃第k个房间,就不能偷第k-1个房间。所以就比较第k-1个房间的dp值,和第k-2个房间的dp值加上第k个房间的值。
class Solution {
public int rob(int[] nums) {
int l = nums.length;
int[] dp = new int[l];
if(l==1){
return nums[0];
}
if(l==2){
return Math.max(nums[0],nums[1]);
}
dp[0] = nums[0];
dp[1] = Math.max(nums[0],nums[1]);
for(int i=2;i<l;i++){
dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[l-1];
}
}
200、岛屿数量
深度优先搜索,如果位置为1,则对其为起始节点进行dfs,在dfs过程中将每个搜到的1都标记为0。
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
if(grid[i][j]=='1'){
bfs(grid,i,j);
count++;
}
}
}
return count;
}
void bfs(char[][] grid,int i,int j){
if(i<0 || i>=grid.length || j<0 || j>=grid[0].length || grid[i][j]=='0'){
return;
}
grid[i][j]='0';
bfs(grid,i-1,j);
bfs(grid,i+1,j);
bfs(grid,i,j-1);
bfs(grid,i,j+1);
}
}
206、反转链表
迭代。遍历链表时,将当前节点的next指针改为指向前一个节点。
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
while(cur!=null){
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
207、课程表
使用一个队列来进行广度优先搜索,初始时,把所有入度为0的节点都放入队列中。
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<List<Integer>> edges = new ArrayList<List<Integer>>();
int[] indeg = new int[numCourses];
for(int i=0;i<numCourses;i++){
edges.add(new ArrayList<Integer>());
}
for(int[] info : prerequisites){
// 先把数组右边列表和左边列表对应起来
edges.get(info[1]).add(info[0]);
// 统计学该课程之前需要学的课程
indeg[info[0]]++;
}
Queue<Integer> queue = new LinkedList<Integer>();
for(int i=0;i<numCourses;i++){
// 把不需要学的课程入队列
if(indeg[i] == 0){
queue.offer(i);
}
}
int visited = 0;
while(!queue.isEmpty()){
// 统计次数,如果为true,则次数应为总课程数,因为每个课程都要入一次队列
visited++;
int u = queue.poll();
for(int v : edges.get(u)){
// 以学会了课程u,把需要提取学习课程u的所有课程的indeg减一
indeg[v]--;
if(indeg[v]==0){
queue.offer(v);
}
}
}
return visited == numCourses;
}
}
208、实现 Trie (前缀树)
字典树。
class Trie {
private Trie[] children;
private boolean isEnd;
public Trie() {
children = new Trie[26];
isEnd = false;
}
public void insert(String word) {
Trie node = this;
for(int i=0;i<word.length();i++){
char ch = word.charAt(i);
int index = ch - 'a';
if(node.children[index]==null){
node.children[index] = new Trie();
}
node = node.children[index];
}
node.isEnd = true;
}
public boolean search(String word) {
Trie node = searchPrefix(word);
return node != null && node.isEnd;
}
public boolean startsWith(String prefix) {
return searchPrefix(prefix) != null;
}
private Trie searchPrefix(String prefix){
Trie node = this;
for(int i=0;i<prefix.length();i++){
char ch = prefix.charAt(i);
int index = ch - 'a';
if(node.children[index]==null){
return null;
}
node = node.children[index];
}
return node;
}
}
215、数组中的第K个最大元素
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k];
}
}
221、最大正方形
动态规划。dp数组中表示以(i,j)为右下角的最大正方形的边长,然后通过dp*dp来比较获得最大值。
class Solution {
public int maximalSquare(char[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
int maxSide = 0;
int dp[][] = new int[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(matrix[i][j]=='0'){
dp[i][j] = 0;
} else{
if(i==0 || j==0){
dp[i][j] = 1;
} else{
dp[i][j] = Math.min(Math.min(dp[i-1][j-1],dp[i][j-1]),dp[i-1][j]) + 1;
}
}
maxSide = Math.max(maxSide,dp[i][j]*dp[i][j]);
}
}
return maxSide;
}
}
226、翻转二叉树
递归
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode left1 = invertTree(root.right);
TreeNode right1 = invertTree(root.left);
root.left = left1;
root.right = right1;
return root;
}
}
234、回文链表
通过快慢指针来取到中间节点。在通过hashmap存储节点的值。
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode fast = head;
ListNode slow = head;
ListNode head1 = head;
Map<Integer,Integer> hsp = new HashMap<>();
int i = 0;
int n = 0;
while(head1 != null){
head1 = head1.next;
n++;
}
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
while(slow != null){
i++;
hsp.put(i,slow.val);
slow = slow.next;
}
while(i>0){
int temp = hsp.get(i);
if(temp != head.val){
return false;
}
i--;
head = head.next;
}
return true;
}
}
236、二叉树的最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(root==p || root==q){
return root;
}
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left!=null && right!=null){
return root;
} else if(left == null){
return right;
} else{
return left;
}
}
}
238、除自身以外数组的乘积
记录左右乘积的数组,每个除自身以外的数组乘积都是:左乘积数组*右乘积数组。
class Solution {
public int[] productExceptSelf(int[] nums) {
int size = nums.length;
int[] left = new int[size];
int[] right = new int[size];
left[0] = 1;
right[size-1] = 1;
for(int i=1;i<size;i++){
left[i] = nums[i-1]*left[i-1];
}
for(int i=size-1;i>0;i--){
right[i-1] = nums[i]*right[i];
}
for(int i=0;i<size;i++){
nums[i] = left[i]*right[i];
}
return nums;
}
}
239、滑动窗口最大值
双端队列手动实现单调队列
首先定义一个双端队列deque
当数组为非空 并且 头结点的范围 不在 [i - k + 1, i] 内时,将队列头弹出 执行deque.peek()
当队列非空,并且队列尾部索引对应数组元素的元素小于nums[i]的时候,将队列尾部弹出,执行deque.peekLast()
将此时的i加入到deque中 执行deque.offer(i)
class Solution {
// 双端队列手动实现单调队列
public int[] maxSlidingWindow(int[] nums, int k) {
ArrayDeque<Integer> deque = new ArrayDeque<>();
int n = nums.length;
int[] res = new int[n-k+1];
int idx = 0;
for(int i=0;i<n;i++){
// 保证当前的要装的i,比队列第一个的差小于k。即队列最多有3个数
while(!deque.isEmpty() && deque.peek()<i-k+1){
deque.poll();
}
// 保证当前的nums[i]的值如果比当前队列末尾的值大的话,直接删除。
while(!deque.isEmpty() && nums[deque.peekLast()]<nums[i]){
deque.pollLast();
}
deque.offer(i);
if(i>=k-1){
res[idx++] = nums[deque.peek()];
}
}
return res;
}
}
240、搜索二维矩阵 II
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int x = 0;
int y = n-1;
while(x<m && y>=0){
if(matrix[x][y] == target){
return true;
} else if(matrix[x][y]>target){
y--;
} else{
x++;
}
}
return false;
}
}
279、完全平方数
class Solution {
public int numSquares(int n) {
int[] f = new int[n + 1];
for (int i = 1; i <= n; i++) {
int minn = Integer.MAX_VALUE;
for (int j = 1; j * j <= i; j++) {
minn = Math.min(minn, f[i - j * j]);
}
f[i] = minn + 1;
}
return f[n];
}
}
283、移动零
class Solution {
public void moveZeroes(int[] nums) {
int m = 0;
int l = nums.length;
for(int i=0;i<l;i++){
if(nums[i] != 0){
nums[m++] = nums[i];
}
}
while(m<l){
nums[m++] = 0;
}
}
}
287、寻找重复数
class Solution {
public int findDuplicate(int[] nums) {
Set<Integer> hst = new HashSet<>();
for(int i=0;i<nums.length;i++){
if(hst.contains(nums[i])){
return nums[i];
}
hst.add(nums[i]);
}
return -1;
}
}
297、二叉树的序列化与反序列化
public class Codec {
public String serialize(TreeNode root) {
return rserialize(root,"");
}
public TreeNode deserialize(String data) {
String[] dataArray = data.split(",");
List<String> dataList = new LinkedList<String>(Arrays.asList(dataArray));
return rdeserialize(dataList);
}
// 序列化
public String rserialize(TreeNode root,String str){
if(root == null){
str += "None,";
} else{
str += str.valueOf(root.val) + ",";
str = rserialize(root.left,str);
str = rserialize(root.right,str);
}
return str;
}
// 反序列化
public TreeNode rdeserialize(List<String> dataList){
if(dataList.get(0).equals("None")){
dataList.remove(0);
return null;
}
TreeNode root = new TreeNode(Integer.valueOf(dataList.get(0)));
dataList.remove(0);
root.left = rdeserialize(dataList);
root.right = rdeserialize(dataList);
return root;
}
}
300、最长递增子序列
动态规划。两重for循环,第一次for循环是循环nums的每一个i,第二次for循环是循环nums中的每个小于i的所有数j。
dp[i] = Math.max(dp[i],dp[j]+1);
class Solution {
public int lengthOfLIS(int[] nums) {
// 动态规划,把所有的dp都置为一
int[] dp = new int[nums.length];
dp[0] = 1;
int max = 1;
for(int i=1;i<nums.length;i++){
dp[i] = 1;
// 循环i之前的所有元素,如果比他们大,比较是当前的dp大还是他们的dp加1大
for(int j=0;j<i;j++){
if(nums[i]>nums[j]){
dp[i] = Math.max(dp[i],dp[j]+1);
}
}
max = Math.max(max,dp[i]);
}
return max;
}
}
301、删除无效的括号
广度优先搜索,每一轮都删除字符串中的1个括号,直到出现合法匹配的字符串为止。
我们进行广度优先搜索时,每次保存上一轮搜索的结果,然后对上一轮已经保存的结果中的每一个字符串尝试所有可能的删除一个括号的方法,然后将保存的结果进行下一轮搜索。在保存结果时,我们可以利用哈希表对上一轮生成的结果去重,从而提高效率。
class Solution {
public List<String> removeInvalidParentheses(String s) {
List<String> result = new ArrayList<>();
if(s.equals("")){
result.add(s);
return result;
}
Deque<String> queue = new ArrayDeque<>();
queue.offer(s);
HashSet<String> set = new HashSet<>();
boolean isFound = false;
// bfs 广度优先
while(!queue.isEmpty()){
String curr = queue.poll();
// 对符合要求的字符串进行入result
if(isValid(curr)){
result.add(curr);
isFound = true;
}
if(isFound){
continue;
}
// 对不符合要求的字符串,将每个只删一个 ( 或者 ) 的字符串进行入队列queue
for(int i=0;i<curr.length();i++){
if(curr.charAt(i) == '(' || curr.charAt(i) == ')'){
String str;
if(i == curr.length()-1){
str = curr.substring(0,curr.length()-1);
} else{
str = curr.substring(0,i) + curr.substring(i+1);
}
if(set.add(str)){
queue.offer(str);
}
}
}
}
if(result.isEmpty()){
result.add("");
}
return result;
}
// 检验字符串是否符合要求
private static boolean isValid(String s){
int left = 0;
for(int i=0;i<s.length();i++){
int curr = s.charAt(i);
if(curr == '('){
left++;
} else if(curr == ')'){
if(left != 0){
left--;
} else{
return false;
}
}
}
return left == 0;
}
}
309、最佳买卖股票时机含冷冻期
class Solution {
public int maxProfit(int[] prices) {
int size = prices.length;
if(size < 2){
return 0;
}
int[][] f = new int[size][3];
f[0][0] = -prices[0];
for(int i=1;i<size;i++){
// 有股票
f[i][0] = Math.max(f[i-1][0],f[i-1][2]-prices[i]);
// 无股票,刚刚卖出,第二天是冷冻期
f[i][1] = f[i-1][0]+prices[i];
// 无股票,不是当天卖出
f[i][2] = Math.max(f[i-1][1],f[i-1][2]);
}
return Math.max(f[size-1][1],f[size-1][2]);
}
}
312、戳气球
i不断缩小,j不断扩大,k在i和j之间。dp[i,j]的意思是在数组i到j的范围内,k为分割戳点的左右加自身的最大数量。
class Solution {
public int maxCoins(int[] nums) {
int n = nums.length;
int[] res = new int[n + 2];
for(int i = 0; i < n + 2; i++){
if(i == 0 || i == n + 1){
res[i] = 1;
}else{
res[i] = nums[i - 1];
}
}
int[][] dp= new int[n+2][n+2];
for(int i=n+1;i>=0;i--){
for(int j=i+1;j<n+2;j++){
for(int k=i+1;k<j;k++){
dp[i][j] = Math.max(dp[i][j],dp[i][k]+dp[k][j]+res[i]*res[k]*res[j]);
}
}
}
return dp[0][n+1];
}
}
322、零钱兑换
动态规划:求从1开始到最终零钱的dp值,然后再把每种硬币类型都考虑一遍。
dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp,amount+1);
dp[0] = 0;
for(int i=1;i<=amount;i++){
for(int j=0;j<coins.length;j++){
if(coins[j]<=i){
dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
}
}
}
return dp[amount] == amount+1 ? -1 : dp[amount];
}
}
递归:
class Solution {
public int coinChange(int[] coins, int amount) {
if(amount<1){
return 0;
}
return dfs(coins,amount,new int[amount]);
}
int dfs(int[] coins,int amount,int[] counts){
if(amount<0){
return -1;
}
if(amount==0){
return 0;
}
if(counts[amount-1]!=0){
return counts[amount-1];
}
int min = Integer.MAX_VALUE;
for(int coin : coins){
int res = dfs(coins,amount-coin,counts);
if(res>=0 && res<min){
min = 1 + res;
}
}
counts[amount-1] = (min == Integer.MAX_VALUE) ? -1:min;
return counts[amount-1];
}
}
337、打家劫舍 III
当 node 被选中时,node 的左右孩子都不能被选中。
当 node 不被选中时,node 的左右孩子可以被选中,也可以不被选中。
class Solution {
Map<TreeNode,Integer> f = new HashMap<>(); //被选中
Map<TreeNode,Integer> g = new HashMap<>(); //不被选中
public int rob(TreeNode root) {
dfs(root);
return Math.max(f.getOrDefault(root, 0), g.getOrDefault(root, 0));
}
void dfs(TreeNode node){
if(node == null){
return;
}
dfs(node.left);
dfs(node.right);
f.put(node,node.val + g.getOrDefault(node.left,0) + g.getOrDefault(node.right, 0));
g.put(node, Math.max(f.getOrDefault(node.left, 0), g.getOrDefault(node.left, 0))
+ Math.max(f.getOrDefault(node.right, 0), g.getOrDefault(node.right, 0)));
}
}
338、比特位计数
class Solution {
public int[] countBits(int n) {
int[] res = new int[n+1];
for(int i=0;i<=n;i++){
res[i] = res[i >> 1] + (i & 1);
}
return res;
}
}
347、前 K 个高频元素
重点:通过map中的value的大小进行排序,根据排序结果取出前k个key。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Arrays.sort(nums);
int size = nums.length;
Map<Integer,Integer> hsp1 = new HashMap<>();
hsp1.put(nums[0],1);
for(int i=1;i<size;i++){
if(nums[i] == nums[i-1]){
hsp1.put(nums[i],hsp1.get(nums[i])+1);
} else{
hsp1.put(nums[i],1);
}
}
Set<Integer> set=hsp1.keySet();
hsp1.entrySet();
List<Map.Entry<Integer,Integer>> list = new ArrayList(hsp1.entrySet());
Collections.sort(list, (o1, o2) -> (o2.getValue() - o1.getValue()));
int[] res = new int[k];
int i=0;
while(i<k){
res[i] = list.get(i).getKey();
i++;
}
return res;
}
}
394、字符串解码
通过两个队列来存储次数和字符串,通过deque.peek().append()可以添加到队列后面。
class Solution {
public String decodeString(String s) {
int i = 0;
char[] arr = s.toCharArray();
Deque<Integer> stack = new ArrayDeque<>();
Deque<StringBuilder> stack2 = new ArrayDeque<>();
stack2.push(new StringBuilder());
while(i<arr.length){
char c = arr[i];
if(c<='9' && c>='0'){
int p = i;
while(i<arr.length && arr[i]<='9' && arr[i]>='0'){
i++;
}
stack.push(Integer.parseInt(s.substring(p,i)));
stack2.push(new StringBuilder());
} else if(c>='a' && c<='z'){
stack2.peek().append(c);
} else if(c==']'){
int times = stack.pop();
StringBuilder last = stack2.pop();
stack2.peek().append(last.toString().repeat(times));
}
i++;
}
return stack2.peek().toString();
}
}
399、除法求值
class Solution {
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
int count=0;
//统计出现的所有字符,并赋予对应的index
Map<String,Integer> map=new HashMap<>();
for (List<String> list:equations){
for (String s:list){
if(!map.containsKey(s)){
map.put(s,count++);
}
}
}
//构建一个矩阵来代替图结构
double[][] graph=new double[count+1][count+1];
//初始化
for (String s:map.keySet()){
int x=map.get(s);
graph[x][x]=1.0;
}
int index=0;
for (List<String> list:equations){
String a=list.get(0);
String b=list.get(1);
int aa=map.get(a);
int bb=map.get(b);
double value=values[index++];
graph[aa][bb]=value;
graph[bb][aa]=1/value;
}
//通过Floyd算法进行运算
int n=count+1;
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
for (int k=0;k<n;k++){
if(j==k||graph[j][k]!=0) continue;
if(graph[j][i]!=0&&graph[i][k]!=0){
graph[j][k]=graph[j][i]*graph[i][k];
}
}
}
}
//直接通过查询矩阵得到答案
double[] res=new double[queries.size()];
for (int i=0;i<res.length;i++){
List<String> q=queries.get(i);
String a=q.get(0);
String b=q.get(1);
if(map.containsKey(a)&&map.containsKey(b)){
double ans=graph[map.get(a)][map.get(b)];
res[i]=(ans==0?-1.0:ans);
}else {
res[i]=-1.0;
}
}
return res;
}
}
406、根据身高重建队列
在二维数组中,对身高升序,然后对同身高的位次降序。然后在对person数组循环的过程中,通过对位次依次的减一,确定最终位置。
class Solution {
public int[][] reconstructQueue(int[][] people) {
int size = people.length;
int[][] res = new int[size][];
Arrays.sort(people,new Comparator<int[]>(){
public int compare(int[] person1,int[] person2){
if(person1[0]!=person2[0]){
return person1[0] - person2[0];
} else{
return person2[1] - person1[1];
}
}
});
for(int[] person : people){
int spaces = person[1] + 1;
for(int i=0;i<size;i++){
if(res[i]==null){
spaces--;
if(spaces==0){
res[i] = person;
break;
}
}
}
}
return res;
}
}
416、分割等和子集
01背包问题,递推公式:dp[i] = dp[i] + dp[i-num] ,对于当前的第i个物品,有拿和不拿两种情况,dp[i]表示不拿的情况,dp[i-num]表示拿的情况,因此要将两者相加。
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
int sum = 0;
for(int n : nums){
sum += n;
}
if(sum%2 != 0){
return false;
}
int target = sum/2;
int[] dp = new int[target+1];
dp[0] = 1;
for(int num : nums){
for(int i=target;i>=num;i--){
dp[i] = dp[i] + dp[i-num];
}
}
return dp[target]!=0;
}
}
437、路径总和 III
递归,使用count作为计数器。先对该节点判断,符合的count加一,然后递归左右节点。
class Solution {
int count = 0;
public int pathSum(TreeNode root, int targetSum) {
if(root == null){
return 0;
}
isNode(root,targetSum);
pathSum(root.left,targetSum);
pathSum(root.right,targetSum);
return count;
}
void isNode(TreeNode root, int targetSum){
if(root == null){
return;
}
targetSum = targetSum - root.val;
if(targetSum == 0){
count++;
}
isNode(root.left,targetSum);
isNode(root.right,targetSum);
}
}
438、找到字符串中所有字母异位词
把相应长度的字母变为数组,排序后根据Arrays.equals(res,ans)比较数组是否相等。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new LinkedList<>();
char[] s1 = s.toCharArray();
int sizep = p.length();
int sizes = s.length();
int[] ans = new int[sizep];
for(int j=0;j<sizep;j++){
ans[j] = p.charAt(j)-'a';
}
Arrays.sort(ans);
int[] res = new int[sizep];
int i=0;
while(i<=sizes-sizep){
for(int j=0;j<sizep;j++){
res[j] = s1[i+j]-'a';
}
Arrays.sort(res);
if(Arrays.equals(res,ans)){
list.add(i);
}
i++;
}
return list;
}
}
448、找到所有数组中消失的数字
通过nums数组本身来操作。
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
int n = nums.length;
List<Integer> res = new ArrayList<>();
for(int num : nums){
int x = (num - 1) % n;
nums[x] += n;
}
for(int i=0;i<n;i++){
if(nums[i] <= n){
res.add(i+1);
}
}
return res;
}
}
461、汉明距离
每次都判断最后一位,如果不相同的话,count加一。然后除2,即向右一移动一位,再做上述比较。
class Solution {
public int hammingDistance(int x, int y) {
int count = 0;
while(x!=0 || y!=0){
if(x%2 != y%2){
count++;
}
x = x/2;
y = y/2;
}
return count;
}
}
494、目标和
回溯:nums,target,走到的位置res,总和sum作为回溯的变量,符合条件后,count加一。
class Solution {
int count = 0;
public int findTargetSumWays(int[] nums, int target) {
dfs(nums,target,0,0);
return count;
}
void dfs(int[] nums,int target,int res,int sum){
if(res == nums.length && sum == target){
count++;
} else if(res<nums.length){
dfs(nums,target,res+1,sum+nums[res]);
dfs(nums,target,res+1,sum-nums[res]);
}
}
}
01背包动态规划:
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int num : nums){
sum += num;
}
int diff = sum - target;
if(diff<0 || diff%2!=0){
return 0;
}
int n = nums.length;
int neg = diff/2; //neg为减的数之和
int[][] dp = new int[n+1][neg+1]; //dp表示在前i个数中选取元素,这些元素之和等于j的方案数。
dp[0][0] = 1;
for(int i=1;i<=n;i++){
int num = nums[i-1];
for(int j=0;j<=neg;j++){
dp[i][j] = dp[i-1][j];
//如果j>=num的话,表明可以选择num,也可以不选num。
if(j>=num){
dp[i][j] += dp[i-1][j-num];
}
}
}
return dp[n][neg];
}
}
538、把二叉搜索树转换为累加树
先求右边的root的值的话,就递归右边。
class Solution {
int num = 0;
public TreeNode convertBST(TreeNode root) {
if(root == null){
return root;
}
convertBST(root.right);
root.val = root.val + num;
num = root.val;
convertBST(root.left);
return root;
}
}
543、二叉树的直径
这里的不一定必须过根节点。
class Solution {
public int diameterOfBinaryTree(TreeNode root) {
if(root == null){
return 0;
}
int leftmax = diameterOfBinaryTree(root.left);
int rightmax = diameterOfBinaryTree(root.right);
return Math.max(
Math.max(leftmax,rightmax),
dfs(root.left) + dfs(root.right)
);
}
int dfs(TreeNode root){
if(root == null){
return 0;
} else{
int leftmax = dfs(root.left);
int rightmax = dfs(root.right);
return Math.max(leftmax,rightmax) + 1;
}
}
}
560、和为 K 的子数组
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
int pre = 0;
HashMap<Integer,Integer> hsp = new HashMap<>();
hsp.put(0,1);
for(int i=0;i<nums.length;i++){
pre += nums[i];
if(hsp.containsKey(pre-k)){
count += hsp.get(pre-k);
}
hsp.put(pre,hsp.getOrDefault(pre,0) + 1);
}
return count;
}
}
581、最短无序连续子数组
new一个相同的数组,对原数组排序,然后不断向中间缩。
class Solution {
public int findUnsortedSubarray(int[] nums) {
if(isSorted(nums)){
return 0;
}
int[] nums1 = new int[nums.length];
for(int i=0;i<nums.length;i++){
nums1[i] = nums[i];
}
Arrays.sort(nums);
int count = 0;
int i = 0;
int j = nums.length-1;
while(nums[i]==nums1[i]){
i++;
}
while(nums[j]==nums1[j]){
j--;
}
return j-i+1;
}
public boolean isSorted(int[] nums) {
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1]) {
return false;
}
}
return true;
}
}
617、合并二叉树
递归
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root2 == null){
return root1;
}
if(root1 == null){
return root2;
}
if(root1!=null && root2!=null){
root1.val += root2.val;
root1.left = mergeTrees(root1.left,root2.left);
root1.right = mergeTrees(root1.right,root2.right);
}
return root1;
}
}
621、任务调度器
class Solution {
public int leastInterval(char[] tasks, int n) {
Map<Character, Integer> freq = new HashMap<Character, Integer>();
for (char ch : tasks) {
freq.put(ch, freq.getOrDefault(ch, 0) + 1);
}
// 任务总数
int m = freq.size();
List<Integer> nextValid = new ArrayList<Integer>();
List<Integer> rest = new ArrayList<Integer>();
Set<Map.Entry<Character, Integer>> entrySet = freq.entrySet();
for (Map.Entry<Character, Integer> entry : entrySet) {
int value = entry.getValue();
nextValid.add(1);
rest.add(value);
}
int time = 0;
for (int i = 0; i < tasks.length; ++i) {
++time;
int minNextValid = Integer.MAX_VALUE;
for (int j = 0; j < m; ++j) {
if (rest.get(j) != 0) {
minNextValid = Math.min(minNextValid, nextValid.get(j));
}
}
time = Math.max(time, minNextValid);
int best = -1;
for (int j = 0; j < m; ++j) {
if (rest.get(j) != 0 && nextValid.get(j) <= time) {
if (best == -1 || rest.get(j) > rest.get(best)) {
best = j;
}
}
}
nextValid.set(best, time + n + 1);
rest.set(best, rest.get(best) - 1);
}
return time;
}
}
647、回文子串
abcde,字符串中要算回文子串,对应每个字符要计算本身和他后面一个两种情况,比如a和ab。
class Solution {
public int countSubstrings(String s) {
int size = s.length();
int count = 0;
for(int i=0;i<2*size-1;i++){
int a = i/2;
int b = i/2 + i%2;
while(a>=0 && b<size && s.charAt(a)==s.charAt(b)){
a--;
b++;
count++;
}
}
return count;
}
}
739、每日温度
对每次的结果都在数组中比较一次。
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int size = temperatures.length;
for(int i=0;i<size;i++){
temperatures[i] = res(temperatures,i,temperatures[i]);
}
return temperatures;
}
int res(int[] temperatures,int i,int num){
int m = i;
while(i<temperatures.length){
if(temperatures[i]<=num){
i++;
} else{
return i-m;
}
}
return 0;
}
}