topcode每日更新觉得不错请关注点赞,你的关注是我的更新动力!!
leetcode - 215. 数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
方法1:使用Priority构建小顶堆,O(nlogk)
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums.length==0 || k<=0) return 0;
//构建一个小顶堆
PriorityQueue<Integer> queue = new PriorityQueue<>();
for(int i=0;i<nums.length;i++){
if(queue.size()<k){
queue.add(nums[i]);
}else if(queue.peek()<nums[i]){
queue.poll();
queue.add(nums[i]);
}
}
return queue.peek();
}
}
1234567891011121314151617
方法2:快速排序,O(nlogn)
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums.length==0 || k<=0) return 0;
int left = 0;
int right = nums.length-1;
quickSort(left,right,nums);
return nums[nums.length-k];
}
private void quickSort(int left, int right, int[] nums) {
if(left>right) return;
int index = getIndex(left,right,nums);
quickSort(left,index-1,nums);
quickSort(index+1,right,nums);
}
private int getIndex(int left, int right, int[] nums) {
int tmp = nums[left];
while (left<right){
while (left<right && nums[right]>=tmp){
right--;
}
nums[left] = nums[right];
while (left<right && nums[left]<=tmp){
left++;
}
nums[right] = nums[left];
}
nums[left] = tmp;
return left;
}
}
leetcode - 206. 反转链表
反转一个单链表。
class Solution {
public ListNode reverseList(ListNode head) {
ListNode begin = null ;
ListNode mid = head ;
while (mid != null){
//last在循环中设定,记录mid的下一个指针
ListNode last = mid.next;
mid.next = begin;
begin = mid;
mid = last;
//可以删除判断,每次last都重新new
//if (last != null){
//判断不超出边界
//last= last.next;
//}
}
return begin;
//return 的不是mid
//mid触碰null,返回begin 放入while (mid != null)
}
}
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null||head.next == null ) return head;
ListNode last = rev erseList(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
3. 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
方法:哈希表
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s==null) return 0;
HashMap<Character,Integer> map = new HashMap<>();
int res = 0;
for(int start = 0,end = 0;end<s.length();end++){
//遇到重复字符时,更新start
if(map.containsKey(s.charAt(end))){
start = Math.max(start,map.get(s.charAt(end))+1);
}
map.put(s.charAt(end),end);
res = Math.max(res,end-start+1);
}
return res;
}
}
12345678910111213141516
leetcode - 15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> threeSum(int[] nums) {
if(nums.length==0) return res;
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(i>0 && nums[i]==nums[i-1]) continue;
int left = i+1;
int right = nums.length-1;
while (left<right){
int sum = nums[left]+nums[right]+nums[i];
if(sum==0){
res.add(Arrays.asList(nums[left],nums[right],nums[i]));
while (left<right && nums[left]==nums[left+1]) left++;
while (left<right && nums[right]==nums[right-1]) right--;
left++;
right--;
}else if(sum<0){
left++;
}else{
right--;
}
}
}
return res;
}
}
123456789101112131415161718192021222324252627
leetcode - 94. 二叉树的中序遍历
给你二叉树的根节点 root
,返回它节点值的 中序 遍历。
方法1:递归
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
if(root==null) return res;
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if(root==null) return;
dfs(root.left);
res.add(root.val);
dfs(root.right);
}
}
123456789101112131415
方法2:迭代
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
if(root==null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
if(node!=null){
if(node.right!=null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left!=null) stack.push(node.left);
}else{
res.add(stack.pop().val);
}
}
return res;
}
}
1234567891011121314151617181920
leetcode - 144. 二叉树的前序遍历
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
方法1:递归
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
if(root==null) return res;
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if(root==null) return;
res.add(root.val);
dfs(root.left);
dfs(root.right);
}
}
123456789101112131415
方法2:迭代
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
if(root==null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
if(node!=null){
if(node.right!=null) stack.push(node.right);
if(node.left!=null) stack.push(node.left);
stack.push(node);
stack.push(null);
}else{
res.add(stack.pop().val);
}
}
return res;
}
}
1234567891011121314151617181920
leetcode - 141. 环形链表
给定一个链表,判断链表中是否有环。如果链表中存在环,则返回 true 。 否则,返回 false 。
方法:快慢指针,快指针走两步,慢指针走一步,两指针相遇的时候就是环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null) return false;
ListNode fast = head;
ListNode slow = head;
while (true){
if(fast==null || fast.next==null) return false;
fast = fast.next.next;
slow = slow.next;
if(fast==slow){
return true;
}
}
}
}
123456789101112131415
leetcode - 142. 环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
方法:快慢指针
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (true){
if(fast==null || fast.next==null) return null;
fast = fast.next.next;
slow = slow.next;
if(fast==slow) break;
}
slow = head;
while (slow!=fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
123456789101112131415161718
leetcode - 199. 二叉树的右视图
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> rightSideView(TreeNode root) {
if(root==null) return res;
dfs(root,0);
return res;
}
private void dfs(TreeNode root, int level) {
if(root==null) return;
//二叉树的层数=res的大小时,说明当前元素还没添加进去
if(res.size()==level){
res.add(root.val);
}
level++;
dfs(root.right,level);
dfs(root.left,level);
}
}
12345678910111213141516171819
leetcode - 160. 相交链表
编写一个程序,找到两个单链表相交的起始节点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode cur1 = headA;
ListNode cur2 = headB;
while (cur1!=cur2){
if(cur1==null){
cur1 = headB;
}else{
cur1 = cur1.next;
}
if(cur2==null){
cur2 = headA;
}else{
cur2 = cur2.next;
}
}
return cur1;
}
}
12345678910111213141516171819
leetcode - 92. 反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
方法:使用两个指针pre和start并移动到要反转的节点处,然后反转即可
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
if(head==null) return null;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
ListNode start = head;
//将pre2移动至要反转的节点位置处
for(int i=0;i<m-1;i++){
pre = pre.next;
start = start.next;
}
//反转链表,反转的次数就是n-m
for(int i=0;i<n-m;i++){
ListNode end = start.next;
ListNode nextStart = start.next.next;
start.next = nextStart;
end.next = pre.next;
pre.next = end;
}
return dummy.next;
}
}
12345678910111213141516171819202122232425
leetcode - 104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
方法:递归
class Solution {
public int maxDepth(TreeNode root) {
if(root==null) return 0;
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
return Math.max(leftDepth,rightDepth)+1;
}
}
12345678
leetcode - 110. 平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
方法:计算当前节点的左右子树的高度,判断高度差;判断左右子树是否是平衡二叉树
class Solution {
public boolean isBalanced(TreeNode root) {
if(root==null) return true;
return Math.abs(dfs(root.left)-dfs(root.right))<=1 && isBalanced(root.left) && isBalanced(root.right);
}
private int dfs(TreeNode root) {
if(root==null) return 0;
int leftDepth = dfs(root.left);
int rightDepth = dfs(root.right);
return Math.max(leftDepth,rightDepth)+1;
}
}
12345678910111213
leetcode - 543. 二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
class Solution {
int maxDepth = 0;
public int diameterOfBinaryTree(TreeNode root) {
if(root==null) return 0;
dfs(root);
return maxDepth;
}
private int dfs(TreeNode root) {
if(root==null) return 0;
int leftDepth = dfs(root.left);
int rightDepth = dfs(root.right);
// 讲过该节点的二叉树的直径的最大值
maxDepth = Math.max(leftDepth+rightDepth,maxDepth);
// 返回该树的高度
return Math.max(leftDepth,rightDepth)+1;
}
}
123456789101112131415161718
leetcode - 53. 最大子序和
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length==0) return 0;
int[] dp = new int[nums.length+1];
dp[0] = nums[0];
int res = dp[0];
for(int i=1;i<nums.length;i++){
if(dp[i-1]<0){
dp[i] = nums[i];
}else{
dp[i] = nums[i]+dp[i-1];
}
res = Math.max(dp[i],res);
}
return res;
}
}
1234567891011121314151617
leetcode - 69. x 的平方根
实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
方法:二分查找
class Solution {
public int mySqrt(int x) {
//注意,x为非负整数,同时X可能会很大
if(x==0) return 0;
long start = 1;
long end = x;
while (start+1<end) {
long mid = start + (end - start) / 2;
if (mid * mid > x) {
end = mid;
} else {
start = mid;
}
}
return (int)start;
}
}
1234567891011121314151617
leetcode - 20. 有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
方法:栈,遇到一个(
就压入一个)
class Solution {
public boolean isValid(String s) {
if(s==null || s.length()==0) return false;
Stack<Character> stack = new Stack<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
stack.push(')');
}else if(s.charAt(i)=='['){
stack.push(']');
}else if(s.charAt(i)=='{'){
stack.push('}');
//如果以上条件都不符合说明为],),}或者是字符和栈顶的不相同
}else{
if(stack.isEmpty()){
return false;
}
if(stack.pop()!=s.charAt(i)){
return false;
}
}
}
return stack.isEmpty();
}
}
123456789101112131415161718192021222324
leetcode - 415. 字符串相加
给定两个字符串形式的非负整数 num1
和num2
,计算它们的和。
方法:双指针
class Solution {
public String addStrings(String num1, String num2) {
//定义两个指针,跟别指向num1和num2末尾
int i = num1.length()-1;
int j = num2.length()-1;
//进位
int carry = 0;
StringBuilder sb = new StringBuilder();
while (i>=0 || j>=0){
int sum = 0;
if(i>=0){
sum = sum + num1.charAt(i)-'0';
i--;
}
if(j>=0){
sum = sum + num2.charAt(j)-'0';
j--;
}
sum = sum+carry;
sb.append(sum%10);
carry = sum/10;
}
if(carry==1){
sb.append("1");
}
return sb.reverse().toString();
}
}
12345678910111213141516171819202122232425262728
leetcode - 33. 搜索旋转排序数组
给你一个整数数组 nums ,和一个整数 target 。该整数数组原本是按升序排列,但输入时在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
方法:二分查找
class Solution {
public int search(int[] nums, int target) {
if(nums.length==0 || nums==null) return 0;
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start+(end-start)/2;
//如果前半段有序
if(nums[start]<nums[mid]){
if(nums[start]<=target && target<=nums[mid]){
end = mid;
}else{
start = mid;
}
}else{
if(nums[mid]<=target && target<=nums[end]){
start = mid;
}else{
end = mid;
}
}
}
if(nums[start]==target) return start;
else if(nums[end]==target) return end;
return -1;
}
}
123456789101112131415161718192021222324252627
leetcode - 876. 链表的中间结点
给定一个头结点为 head
的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
方法:快慢指针,需要分两种情况,如果链表长度为奇数满足fast!=null ,如果链表长度为偶数满足fast.next!=null
class Solution {
public ListNode middleNode(ListNode head) {
if(head==null) return null;
ListNode fast = head;
ListNode slow = head;
while (fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
123456789101112
leetcode - 234. 回文链表
请判断一个链表是否为回文链表。
class Solution {
public boolean isPalindrome(ListNode head) {
if(head==null) return true;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
//找到链表的中间节点
while (fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
}
//从中间节点处断开链表,并将后半部分反转
ListNode cur = slow.next;
slow.next = null;
ListNode pre = null;
while (cur!=null){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
//让前后段链表的值进行比较
slow = head;
while (slow!=null && pre!=null){
if(pre.val==slow.val){
pre = pre.next;
slow = slow.next;
}else{
return false;
}
}
return true;
}
}
123456789101112131415161718192021222324252627282930313233343536373839
leetcode - 101. 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
return dfs(root.left,root.right) ;
}
private boolean dfs(TreeNode A, TreeNode B) {
if(A==null && B!=null) return false;
if(A!=null && B==null) return false;
if(A==null && B==null) return true;
return A.val==B.val && dfs(A.left,B.right) && dfs(A.right, B.left);
}
}
12345678910111213
leetcode - 62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。问总共有多少条不同的路径?
方法:动态规划
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for(int i=0;i<m;i++){
dp[i][0] = 1;
}
for(int j=0;j<n;j++){
dp[0][j] = 1;
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
}
1234567891011121314151617
leetcode - 63. 不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
for(int i=0;i<obstacleGrid.length;i++){
if(obstacleGrid[i][0]==1) break;
dp[i][0] = 1;
}
for(int j=0;j<obstacleGrid[0].length;j++){
if(obstacleGrid[0][j]==1) break;
dp[0][j] = 1;
}
for(int i=1;i<obstacleGrid.length;i++){
for(int j=1;j<obstacleGrid[0].length;j++){
if(obstacleGrid[i][j]==1) dp[i][j] = 0;
else{
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[obstacleGrid.length-1][obstacleGrid[0].length-1];
}
}
12345678910111213141516171819202122
leetcode - 5. 最长回文子串
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
方法:动态规划
class Solution {
public String longestPalindrome(String s) {
if(s.length()==0) return null;
//dp[i][j]代表[i,j]之间的字符串是否是回文子串
boolean[][] dp = new boolean[s.length()][s.length()];
dp[0][0] = true;
int maxlen = 0;
int begin = 0;
for(int j=0;j<s.length();j++){
for(int i=0;i<=j;i++){
//判断dp[i][j]是否是回文子串:dp[i+1][j-1]是回文子串并且当前两个字符相等
dp[i][j] = s.charAt(i)==s.charAt(j) && (j-i<=2||dp[i+1][j-1]);
if(dp[i][j] && j-i+1>=maxlen){
maxlen = j-i+1;
begin = i;
}
}
}
return s.substring(begin,begin+maxlen);
}
}
123456789101112131415161718192021
leetcode - 647. 回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
方法:动态规划
class Solution {
public int countSubstrings(String s) {
if(s.length()==0) return 0;
int count = 0;
boolean[][] dp = new boolean[s.length()][s.length()];
dp[0][0] = true;
for(int j=0;j<s.length();j++){
for(int i=0;i<=j;i++){
dp[i][j] = s.charAt(i)==s.charAt(j) && (j-i<=2||dp[i+1][j-1]);
if(dp[i][j]){
count++;
}
}
}
return count;
}
}
1234567891011121314151617
leetcode - 78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
**说明:**解集不能包含重复的子集。
方法:递归回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
if(nums.length==0) return res;
dfs(nums,new ArrayList<Integer>(),0);
return res;
}
private void dfs(int[] nums, ArrayList<Integer> path, int start) {
res.add(new ArrayList<>(path));
for(int i=start;i<nums.length;i++){
path.add(nums[i]);
//这里需要注意,不能有重复的,[1,2,3]和[1,3,2]是相同的
dfs(nums,path,i+1);
path.remove(path.size()-1);
}
}
}
123456789101112131415161718
leetcode - 46. 全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
方法:递归回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
if(nums.length==0) return res;
boolean[] used = new boolean[nums.length];
dfs(nums,new ArrayList<Integer>(),used);
return res;
}
private void dfs(int[] nums, ArrayList<Integer> path, boolean[] used) {
if(path.size()==nums.length){
res.add(new ArrayList<Integer>(path));
}
for(int i=0;i<nums.length;i++){
if(used[i]) continue;
path.add(nums[i]);
used[i] = true;
dfs(nums,path,used);
path.remove(path.size()-1);
used[i] =false;
}
}
}
1234567891011121314151617181920212223
leetcode - 47. 全排列 II
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
方法:递归回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums.length==0) return res;
Arrays.sort(nums);
boolean[] used = new boolean[nums.length];
dfs(nums,new ArrayList<Integer>(),used);
return res;
}
private void dfs(int[] nums, ArrayList<Integer> path, boolean[] used) {
if(path.size()==nums.length){
res.add(new ArrayList<Integer>(path));
return;
}
for(int i=0;i<nums.length;i++){
if(used[i]) continue;
if(i>0 && nums[i]==nums[i-1] && used[i-1]==false) continue;
path.add(nums[i]);
used[i] = true;
dfs(nums,path,used);
path.remove(path.size()-1);
used[i] =false;
}
}
}
1234567891011121314151617181920212223242526272829
leetcode - 39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。
方法:递归回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates.length==0) return res;
dfs(candidates,new ArrayList<Integer>(),target,0);
return res;
}
private void dfs(int[] candidates, ArrayList<Integer> path, int target,int start) {
if(target==0){
res.add(new ArrayList<>(path));
return;
}
for(int i=start;i<candidates.length;i++){
if(target<candidates[i]) continue;
path.add(candidates[i]);
target = target - candidates[i];
//因为可以重复选择,因此是i而不是i+1
dfs(candidates,path,target,i);
path.remove(path.size()-1);
target = target + candidates[i];
}
}
}
12345678910111213141516171819202122232425
leetcode - 40. 组合总和 II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
方法:递归回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if(candidates.length==0) return res;
Arrays.sort(candidates);
boolean[] used = new boolean[candidates.length];
dfs(candidates,new ArrayList<Integer>(),target,0,used);
return res;
}
private void dfs(int[] candidates, ArrayList<Integer> path, int target,int start,boolean[] used) {
if(target==0){
res.add(new ArrayList<>(path));
return;
}
for(int i=start;i<candidates.length;i++){
if(used[i]) continue;
if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==false) continue;
if(target<candidates[i]) continue;
path.add(candidates[i]);
target = target - candidates[i];
used[i] = true;
dfs(candidates,path,target,i,used);
used[i] = false;
path.remove(path.size()-1);
target = target + candidates[i];
}
}
}
1234567891011121314151617181920212223242526272829303132
leetcode - 70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
**注意:**给定 n 是一个正整数。
方法:动态规划
class Solution {
public int climbStairs(int n) {
if(n==0) return 0;
if(n==1) return 1;
if(n==2) return 2;
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
for(int i=3;i<=n;i++){
dp[i] = dp[i-1]+dp[i-2];
}
return dp[n];
}
}
123456789101112131415
leetcode - 1143. 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
方法:动态规划
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp = new int[text2.length()+1][text1.length()+1];
dp[0][0] = 0;
for(int i=1;i<=text2.length();i++){
for(int j=1;j<=text1.length();j++){
if(text1.charAt(j-1)==text2.charAt(i-1)){
dp[i][j] = dp[i-1][j-1]+1;
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[text2.length()][text1.length()];
}
}
12345678910111213141516
leetcode - 704. 二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
class Solution {
public int search(int[] nums, int target) {
if(nums.length==0) return 0;
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start +(end-start)/2;
if(nums[mid]<target){
start = mid;
}else{
end = mid;
}
}
if(nums[start]==target) return start;
if(nums[end]==target) return end;
return -1;
}
}
123456789101112131415161718
leetcode - 300. 最长上升子序列
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length==0) return 0;
int[] dp = new int[nums.length];
int res = 0;
for(int i=0;i<nums.length;i++){
dp[i] = 1;
for(int j=0;j<i;j++){
//如果前面的数比当前nums[i]大,将长度加1,就将每次计算的dp[i]进行比较
if(nums[i]>nums[j]){
dp[i] = Math.max(dp[j]+1,dp[i]);
}
}
res = Math.max(res,dp[i]);
}
return res;
}
}
123456789101112131415161718
排序算法 - 冒泡排序算法
时间复杂度:O(n^2)
class Solution {
public static void main(String[] args) {
int[] arr = {15,23,7,47};
buboolSort(arr);
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
public static int[] buboolSort(int[] nums) {
//第一个for循环代表需要比较多少轮
for(int i=0;i<nums.length-1;i++){
/**
* 在每轮排序中,比较相邻两个数的大小,如果前面的数比后面的数大就交换位置
* 第一轮排序i=0,n个数需要比较n-1次
* 第二轮排序i=1,第一大的数已经确定不需要再进行比较,n-1-1次
* 第三轮排序i=2,第二大的数已经确定不需要再进行比较,n-1-1-1次
*/
for(int j=0;j<nums.length-1-i;j++){
//如果前面的数比后面的数大,就交换位置
if(nums[j]>nums[j+1]){
int tmp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = tmp;
}
}
}
return nums;
}
}
1234567891011121314151617181920212223242526272829
排序算法 - 快速排序算法
时间复杂度:O(nlogn)
class Solution {
public static void main(String[] args) {
int[] arr = {15,23,7,47};
int start = 0;
int end = arr.length-1;
quickSort(arr,start,end);
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
public static void quickSort(int[] nums,int start,int end) {
if(start>end) return;
int index = getIndex(nums,start,end);
quickSort(nums,start,index-1);
quickSort(nums,index+1,end);
}
private static int getIndex(int[] nums, int start, int end) {
int tmp = nums[start];
while (start<end){
while (start<end && nums[end]>=tmp){
end--;
}
nums[start] = nums[end];
while (start<end && nums[start]<=tmp){
start++;
}
nums[end] = nums[start];
}
nums[start] = tmp;
return start;
}
}
123456789101112131415161718192021222324252627282930313233
排序算法 - 插入排序算法
时间复杂度:o(n^2)
class Solution {
public static void main(String[] args) {
int[] arr = {15,23,7,47};
int start = 0;
int end = arr.length-1;
quickSort(arr);
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
public static void quickSort(int[] nums) {
for(int i=1;i<nums.length;i++){
int insertNum = nums[i];
int insertIndex = i;
while (insertIndex>0 && nums[insertIndex-1]>insertNum){
nums[insertIndex] = nums[insertIndex-1];
insertIndex--;
}
nums[insertIndex] = insertNum;
}
}
}
12345678910111213141516171819202122
排序算法 - 选择排序算法
时间复杂度:O(n^2)
class Solution {
public static void main(String[] args) {
int[] arr = {15,23,7,47};
int start = 0;
int end = arr.length-1;
selectSort(arr);
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
public static void selectSort(int[] nums) {
for(int i=0;i<nums.length-1;i++){
int minValue = nums[i];
int minIndex = i;
for(int j=i+1;j<nums.length;j++){
if(nums[j]<minValue){
minValue = nums[j];
minIndex = j;
}
}
nums[minIndex] = nums[i];
nums[i] = minValue;
}
}
}
12345678910111213141516171819202122232425
设计模式 - 饿汉式单例模式
class Single{
//饿汉式直接创建对象
private static Single single = new Single();
private Single(){};
//通过公共的构造方法返回对象
public static Single getInstance(){
return single;
}
}
123456789
设计模式 - 懒汉式单例模式
class Single{
private static Single single;
private Single(){};
public static Single getSingle(){
if(single==null){
single = new Single();
}
return single;
}
}
12345678910
线程安全,双检锁:
class Single{
private static volatile Single single;
private Single(){};
public static Single getSingle(){
if(single==null){
synchronized (Single.class){
if(single==null){
single = new Single();
}
}
}
return single;
}
}
1234567891011121314
多线程 - 两种方式创建线程
方式1:使用Thread类创建两个线程并启动
class Test{
public void test(){
Thread t1 = new Thread("t1"){
@Override
public void run(){
System.out.println("线程t1");
}
};
t1.start();
Thread t2 = new Thread("t2"){
@Override
public void run(){
System.out.println("线程t2");
}
};
t2.start();
}
}
12345678910111213141516171819
方式2:使用Runnable接口创建线程类,先创建线程主体,再传入Thread构造方法
class Demo{
public void test(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("线程主体1");
}
};
//向Thread类的构造方法中传入Runnable变量
Thread t1 = new Thread(r1,"t1");
t1.start();
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("线程主体2");
}
};
Thread t2 = new Thread(r2,"t2");
t2.start();
}
}
12345678910111213141516171819202122
多线程 - 创建两个线程
class Test{
//共享变量
private static int count = 0;
//在main线程中创建两个线程t1和t2
public static void main(String[] args){
Thread t1 = new Thread("t1"){
@Override
public void run(){
for(int i=0;i<100;i++){
count++;
}
}
};
Thread t2 = new Thread("t2"){
@Override
public void run(){
for(int i=0;i<100;i++){
count--;
}
}
};
t1.start();
t2.start();
}
}
12345678910111213141516171819202122232425
解决线程安全问题:
class Test{
//共享变量
private static volatile int count = 0;
private static Object object = new Object();
//在main线程中创建两个线程t1和t2
public static void main(String[] args){
Thread t1 = new Thread("t1"){
@Override
public void run(){
for(int i=0;i<100;i++){
synchronized (object){
count++;
}
}
}
};
Thread t2 = new Thread("t2"){
@Override
public void run(){
for(int i=0;i<100;i++){
synchronized (object){
count--;
}
}
}
};
t1.start();
t2.start();
}
}
123456789101112131415161718192021222324252627282930
多线程- 生产者和消费者模型
//创建一个消息类
class Message{
private int id;
private Object value;
public Message(int id,Object value){
this.id = id;
this.value = value;
}
public void setId(int id){
this.id = id;
}
public int getId(){
return id;
}
public void setValue(Object value){
this.value = value;
}
public Object getValue(){
return value;
}
}
//创建一个生产者消费者
class MessageQueue{
//创建一个消息队列,用来存放消息
LinkedList<Message> queue = new LinkedList<>();
private int capacity;
public MessageQueue(int capacity){
this.capacity = capacity;
}
//生产者线程生产消息
public void put(Message message){
synchronized (queue){
//如果队列是满的,生产者线程在队列上等待
while (queue.size()==capacity){
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//队列不满了,将消息加入队列的尾部
queue.addLast(message);
//唤醒等待中的消费者消费者线程,队列不空了
queue.notifyAll();
}
}
//消费者消费消息
public Message get(){
synchronized (queue){
while (queue.isEmpty()){
try {
queue.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
//队列不空了,消费消息,从队列中取出头部的第一个消息消费
Message message = queue.removeFirst();
queue.notifyAll();
return message;
}
}
}