解题-->力扣
1.合并二叉树
解题思路:
如果两个结点都为空的话,直接返回空;
如果两个结点其中之一为空的话,直接返回一个不为空的结点;
如果两个结点都不为空的话,就新创建一个结点,新结点的值是两个结点值之和。
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1==null && root2==null){
return null;
}else if(root1==null || root2==null){
return root1==null?root2:root1;
}else{
TreeNode temp=new TreeNode(root1.val+root2.val);
temp.left=mergeTrees(root1.left,root2.left);
temp.right=mergeTrees(root1.right,root2.right);
return temp;
}
}
}
2.盛最多水的容器
解题思路:
双指针法:
定义两个变量,一个指向数组开头(left=0),一个指向数组最后一个位置(right=height.length-1),开始while循环,计算两个变量之间组成的面积,宽是两个变量之间的差值,高是取两个变量对应的数组元素的最小值。其中max代表组成的最大面积,max每次需要和算出来的面积进行比较,取出最大值。
如果左边(left)对应的数组元素小于等于right对应的数组元素,就将左边的(left)往右边挪一下,否则,右边(right)的往左挪一下。
class Solution {
public int maxArea(int[] height) {
int left=0;
int right=height.length-1;
int max=0;
while(left<=right){
int area=(right-left)*Math.min(height[left],height[right]);
max=Math.max(area,max);
if(height[left]<=height[right]){
left++;
}else{
right--;
}
}
return max;
}
}
3.三数之和
解题思路:
1.先将数组进行排序;
2.从0下标开始遍历数组,left取i+1;right取nums.length-1,然后将三个下标对应的元素相加,最后结果值如果等于0,就将这三个下标所对应的元素借助Arrays.asList(),将这三个数组元素转换成一个list,加入到Set当中,Set集合框架提供HashSet类作为实现设置接口,这个特点就是:不添加重复元素。
3.如果三个下标对应的数组元素相加之后大于0,就证明right取大了,right下标需要往前挪一挪(right–);
4.相反,如果三个下标对应的数组元素相加之后小于0,就证明left取小了left下标需要往后挪一挪(left++)。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
Set<List<Integer>> set=new HashSet<>();
for(int i=0;i<nums.length;i++){
int left=i+1;
int right=nums.length-1;
while(left<right){
int temp=nums[left]+nums[right]+nums[i];
if(temp==0){
set.add(Arrays.asList(nums[i],nums[left],nums[right]));
left++;
right--;
}else if(temp>0){
right--;
}else{
left++;
}
}
}
List<List<Integer>> list=new ArrayList<>();
list.addAll(set);
return list;
}
}
4.电话号码的字母组合
用循环方式解决此题目:
1.先判断这个字符串是否为空,如果为空,就直接返回finalList即可;
2.字符串不为空的情况下,创建一个hashMap,来放这些不同的数字对应的字符串;
3.遍历这个字符串,先将finalList加一个“”,这个目的是:在第一次遍历的时候,finalList的size大小为0,就无法循环添加hashMap取出的字符串,所以,finalList.add(“”):这个目的是:使finalList的size大小为1;然后,调用add()方法,传参是:(finalList,hashMap.get(digit.charAt(i));
4.两层for循环,完成字符组合的操作。
class Solution {
public static List<String> letterCombinations(String digits) {
List<String> finalList=new ArrayList<>();
if("".equals(digits)){
return finalList;
}
HashMap<Character,String> hashMap=new HashMap<>();
hashMap.put('2',"abc");
hashMap.put('3',"def");
hashMap.put('4',"ghi");
hashMap.put('5',"jkl");
hashMap.put('6',"mno");
hashMap.put('7',"pqrs");
hashMap.put('8',"tuv");
hashMap.put('9',"wxyz");
finalList.add("");
for(int i=0;i<digits.length();i++){
finalList=add(finalList,hashMap.get(digits.charAt(i)));
}
return finalList;
}
public static List<String> add(List<String> list,String ret){
List<String> newList=new ArrayList<>();
for(int i=0;i<list.size();i++){
for(int j=0;j<ret.length();j++){
newList.add(list.get(i)+ret.charAt(j));
}
}
return newList;
}
}
5.删除链表的倒数第N个结点
第一种解题思路:
计算出链表的长度,链表需要走的长度是:temp=链表长度-n;
进入for循环i的初始值为0,i<temp,这个目的是:为了找到待删除结点的上一个结点。
退出循环后,将move.next=move.next.next;
再返回dummy.next即可。
这种方法的注意点:需要定义一个傀儡结点,让这个傀儡结点的下一个结点指向head;这个的目的是:如果待删除的结点是链表中的第一个结点。
2.在进入for循环之前,需要判定一下,结点为1个,n=1的这种情况,如果符合这种情况,返回null即可。这个的目的是为了防止后续move.next.next会出现空指针异常的情况。
class Solution {
public static ListNode removeNthFromEnd(ListNode head, int n) {
//第一种解法:
ListNode ret=new ListNode(-1);
ret.next=head;
ListNode move=ret;
ListNode listNode=head;
int length=countLength(listNode);
int temp=length-n;
if(length==1 && n==1){
return null;
}
for(int i=0;i<temp;i++){
move=move.next;
}
move.next=move.next.next;
return ret.next;
}
public static int countLength(ListNode listNode){
int length=0;
while(listNode!=null){
length++;
listNode=listNode.next;
}
return length;
}
}
第二种解题思路:栈
1.创建一个傀儡结点,让傀儡结点的下一个结点指向head;
2.创建一个栈,先遍历整个链表,让整个链表中的结点全部放在栈中,然后再for循环,i初始条件是:i=1;终止条件是:i<=n;然后,让栈中元素出栈;
3.退出循环之后,此时,栈顶元素是待删除结点的上一个结点,就可以直接让ret.next=ret.next.next;
4.返回dummy.next即可。
class Solution {
public static ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
Stack<ListNode> stack=new Stack<>();
ListNode temp=dummy;
while(temp!=null){
stack.push(temp);
temp=temp.next;
}
for(int i=1;i<=n;i++){
stack.pop();
}
if(stack.isEmpty()){
return null;
}
ListNode ret=stack.peek();
ret.next=ret.next.next;
return dummy.next;
}
}
第三种解题思路:双指针
1.定义一个傀儡结点,让傀儡结点的下一个结点指向head;
2.定义两个变量,fast和slow,让fast走n步;
3.然后while循环,退出条件是fast.next!=null;在循环里面需要实现fast走一步,slow走一步;
4.当前退出循环后,slow指向的结点是待删除结点的上一个结点,所以,slow.next=slow.next.next;
5.返回dummy.next。
class Solution {
public static ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(-1);
dummy.next=head;
ListNode fast=dummy;
ListNode slow=dummy;
for(int i=1;i<=n;i++){
fast=fast.next;
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return dummy.next;
}
}
6.括号生成
class Solution {
List<String> ret=new ArrayList<>();
public List<String> generateParenthesis(int n) {
String s="";
dfs(s,ret,n,n);
return ret;
}
public static void dfs(String s,List<String> ret,int left,int right){
if(left==0 && right==0){
ret.add(s);
return;
}
if(left>0){
s+="(";
dfs(s,ret,left-1,right);
s=s.substring(0,s.length()-1);
}
if(right>left){
s+=")";
dfs(s,ret,left,right-1);
s=s.substring(0,s.length()-1);
}
}
}
7.下一个排列
解题思路:
class Solution {
public void nextPermutation(int[] nums) {
if(nums==null || nums.length==0){
return;
}
int j=nums.length-1;
while(j>0){
if(nums[j]<=nums[j-1]){
j--;
}else{
int index=j-1;
while(j<nums.length && nums[j]>nums[index]){
j++;
}
j--;
int temp=nums[index];
nums[index]=nums[j];
nums[j]=temp;
reverse(nums,index+1);
return;
}
}
reverse(nums,0);
}
public static void reverse(int[] nums,int index){
int i=index;
int j=nums.length-1;
while (i<j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
i++;
j--;
}
}
}
8.搜索旋转排序数组
解法一:
暴力求解法,从头到尾去遍历数组
class Solution {
public int search(int[] nums, int target) {
for(int i=0;i<nums.length;i++){
if(target==nums[i]){
return i;
}
}
return -1;
}
}
解法二:二分搜索
二分搜索法的前提是:基于有序的数组。
而这个题目,经过旋转之后,只有一半是有序的,是递增的。
在这个题目中,需要先判断 左边对应的元素 是否小于中间下标对应的元素,如果小于的话,就说明左边是有序的元素,则,判断target是否在左边的范围内,如果在,就递归调用,参数end改成mid-1;如果不在左边范围内,就递归调用,把参数start改成start+1;
对应右边也是这样的操作。
class Solution {
public static int search(int[] nums, int target) {
int start=0;
int end=nums.length-1;
int ret=FindIndex(nums,start,end,target);
return ret;
}
public static int FindIndex(int[] nums,int start,int end,int target){
if(start>end){
return -1;
}
int mid=(start+end)/2;
if(nums[mid]==target){
return mid;
}
if(nums[start]==target){
return start;
}
if(nums[end]==target){
return end;
}
if(nums[start]<nums[mid]){
if(nums[start]<target && target<nums[mid] ){
return FindIndex(nums,start,mid-1,target);
}else{
return FindIndex(nums,mid+1,end,target);
}
}else{
if(nums[mid]<target && target<nums[end]){
return FindIndex(nums,mid+1,end,target);
}else{
return FindIndex(nums,start,mid-1,target);
}
}
}
}
9.在排序数组中查找元素的第一个和最后一个位置
解题思路:
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] index=new int[2];
if(nums.length==0){
return new int[]{-1,-1};
}
index[0]=FindLeft(nums,target);
index[1]=FindRight(nums,target);
return index;
}
public static int FindLeft(int[] nums,int target){
int left=-1;
int right=nums.length-1;
while(left+1<right){
int mid=(right+left)/2;
if(nums[mid]<target){
left=mid;
}else{
right=mid;
}
}
if(nums[right]==target){
return right;
}
return -1;
}
public static int FindRight(int[] nums,int target){
int left=0;
int right=nums.length;
while(left+1<right){
int mid=(left+right)/2;
if(nums[mid]<=target){
left=mid;
}else{
right=mid;
}
}
if(nums[left]==target){
return left;
}
return -1;
}
}
10.组合总和
解题思路:
class Solution {
List<List<Integer>> result=new ArrayList<>();
List<Integer> list=new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
int start=0;
Find(candidates,start,target);
return result;
}
public void Find(int[] candidates,int start,int target){
if(target==0){
result.add(new ArrayList<>(list));
return;
}
for(int i=start;i<candidates.length;i++){
if(candidates[start]>target){
break;
}
list.add(candidates[i]);
Find(candidates,i,target-candidates[i]);
list.remove(list.size()-1);
}
}
}