leetcode_数组

15、3sum

Given an array nums of n integers, are there elements abc in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

思路:
1、先对数组排序;
2、在知道一个值的情况下,求另外两个值的和;
3、求另外两个值的和采用双向指针;

public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> alist = new ArrayList<List<Integer>>();
        for(int i = 0; i < nums.length - 2; i++){
            if(i == 0 || (i > 0 && nums[i] != nums[i - 1])){ //避免了第一个值重复
                int lo = i + 1; 
                int hi = nums.length - 1;
                int sum = 0 - nums[i];
                while(lo < hi){
                    if(nums[lo] + nums[hi] == sum){
                        alist.add(Arrays.asList(nums[i], nums[lo], nums[hi]));
                        while(lo < hi && nums[lo] == nums[lo + 1]) lo++;
                        while(lo < hi && nums[hi] == nums[hi - 1]) hi--;
                        lo++;
                        hi--;
                    }else if(nums[lo] + nums[hi] < sum) lo++;
                    else hi--;
                }
            }
        }
        return alist;
    }

Arrays.asList

 * 本类演示了Arrays类中的asList方法 
 * 通过四个段落来演示,体现出了该方法的相关特性. 
 *  
 * (1) 该方法对于基本数据类型的数组支持并不好,当数组是基本数据类型时不建议使用 
 * (2) 当使用asList()方法时,数组就和列表链接在一起了. 
 *     当更新其中之一时,另一个将自动获得更新。 
 *     注意:仅仅针对对象数组类型,基本数据类型数组不具备该特性 
 * (3) asList得到的数组是的没有add和remove方法的 
 *  
 * 阅读相关:通过查看Arrays类的源码可以知道,asList返回的List是Array中的实现的 
 * 内部类,而该类并没有定义add和remove方法.另外,为什么修改其中一个,另一个也自动 
 * 获得更新了,因为asList获得List实际引用的就是数组 

16. 3Sum Closest

Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

Example:

Given array nums = [-1, 2, 1, -4], and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

思路:
1、比较三数和与target的大小
2、更新左右指针,不断向target靠近(sum > target 减小hi,否则增加lo)

public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int res = Integer.MAX_VALUE;
        int index = 0;
        for(int i = 0; i < nums.length - 2; i++){
                int lo = i + 1; 
                int hi = nums.length - 1;
                while(lo < hi){
                    int sum = nums[i] + nums[lo] + nums[hi];
                    if(res > Math.abs(sum - target)){
                        res = Math.abs(sum - target);
                        index = sum;  
                        if(res == 0) return target;                
                    }
                    if(target < sum) hi--;
                    else lo++;
                }
            
        }
        return index;
    }

18. 4Sum

Given an array nums of n integers and an integer target, are there elements abc, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

思路:
四数和问题转化为三数和问题,多一个循环

public List<List<Integer>> fourSum(int[] nums, int target) {
          Arrays.sort(nums);
		 List<List<Integer>> aList = new ArrayList<List<Integer>>();
		 for (int i = 0; i < nums.length - 3; i++) {
			 if(i == 0 ||  (i > 0 && nums[i] != nums[i - 1])) {
				 int curtarget = target - nums[i];
				 //求三数和的问题
				 for(int start = i + 1; start < nums.length - 2; start++) {
					 if(start == i + 1 || (start > i + 1 && 
                                           nums[start] != nums[start - 1])) {
						 int lo = start + 1;
						 int hi = nums.length - 1;
						 while(lo < hi) {
							 int sum = nums[start] + nums[lo] + nums[hi];
							 if(sum == curtarget) {
								 aList.add(Arrays.asList(nums[i], nums[start],
                                                         nums[lo],nums[hi]));
								 while(lo < hi && nums[lo] == nums[lo + 1]) lo++;
								 while(lo < hi && nums[hi] == nums[hi - 1]) hi--;
								 lo++;
								 hi--;
							 }else if(sum > curtarget) {
								 hi--;
							 }else {
								 lo++;
							 }
						 }
					 }
				 }
			 }
					
		}
		 return aList;
    }

求K数和问题通用方式

问题分析如下
1、2sum Problem
2、Reduce K sum problem to K – 1 sum Problem(使用递归)
Time complexity is O(N^(K-1)).
=====================================================================================

    public class Solution {
        int len = 0;
        public List<List<Integer>> fourSum(int[] nums, int target) {
            len = nums.length;
            Arrays.sort(nums);
            return kSum(nums, target, 4, 0);
        }
       private ArrayList<List<Integer>> kSum(int[] nums, int target, int k, int index) {
            ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
            if(index >= len) {
                return res;
            }
            if(k == 2) {
            	int i = index, j = len - 1;
            	while(i < j) {
                    //find a pair
            	    if(target - nums[i] == nums[j]) {
            	    	List<Integer> temp = new ArrayList<>();
                    	temp.add(nums[i]);
                    	temp.add(target-nums[i]);
                        res.add(temp);
                        //skip duplication
                        while(i<j && nums[i]==nums[i+1]) i++;
                        while(i<j && nums[j-1]==nums[j]) j--;
                        i++;
                        j--;
                    //move left bound
            	    } else if (target - nums[i] > nums[j]) {
            	        i++;
                    //move right bound
            	    } else {
            	        j--;
            	    }
            	}
            } else{
                for (int i = index; i < len - k + 1; i++) {
                    //use current number to reduce ksum into k-1sum
                    ArrayList<List<Integer>> temp = kSum(nums, target - nums[i], k-1, i+1);
                    if(temp != null){
                        //add previous results
                        for (List<Integer> t : temp) {
                            t.add(0, nums[i]);
                        }
                        res.addAll(temp);
                    }
                    while (i < len-1 && nums[i] == nums[i+1]) {
                        //skip duplicated numbers
                        i++;
                    }
                }
            }
            return res;
        }
    }

31. Next Permutation

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place and use only constant extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

题意理解:
数组从后往前看找到第一个下降的数,
然后在从后往前找到第一个比刚找的数大的数,
两者交换,
再将第一个位置之后的数据转置一下。

public void nextPermutation(int[] nums) {
       int pivot = nums.length - 1;
        while (pivot > 0 && nums[pivot] <= nums[pivot-1]) {
            pivot--;
        }
        if (pivot != 0) {
            int nextPivot = nums.length - 1;
            while (pivot - 1 < nextPivot && nums[pivot-1] >= nums[nextPivot]) {
                nextPivot--;
            }
            swap(nums, pivot-1, nextPivot);
        }
        reverseArray(nums, pivot, nums.length - 1);
    } 
    private void reverseArray(int[] nums, int start, int end) {
        while (start < end) {
            swap(nums, start++, end--);
        }
    }
	public void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

33. Search in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm's runtime complexity must be in the order of O(log n).

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

思路:
直接比较中间位置
和第一个元素做比较看中间位置在哪个半区
在相应的半区更新左右节点,做二分查找

 public int search(int[] nums, int target) {
        
        if(nums.length < 1 || nums == null)
            return -1;
        int lo = 0;
        int hi = nums.length - 1;
        while(lo < hi){
            int mid = lo + ((hi - lo) >> 1);
            if(nums[mid] >= nums[lo]){  //确定中间值落在哪个区域,这里是落在大半区
                if(target <= nums[mid] && target >= nums[lo]) hi = mid;
                else lo = mid + 1;
            }else{          //落在小半区
                if(target > nums[mid] && target <= nums[hi]) lo = mid + 1;
                else hi = mid;
            }
        }
        return nums[lo] == target ? lo : -1;
    }

81. Search in Rotated Sorted Array II

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).

You are given a target value to search. If found in the array return true, otherwise return false.

Example 1:

Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true

Example 2:

Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false

思路:
二分查找
由于会出现第一个值和最后一个值相等的情况,所以应该比较中点值和末尾值(hi)
mid大于hi,在前半区;
mid小于hi,在后半区;
等于时,不论时前面还是后面,移动lo,hi走到不等的区域;

public boolean search(int[] nums, int target) {
        if(nums == null || nums.length < 1) 
            return false;
        int lo = 0;
        int hi = nums.length - 1;
        while(lo <= hi){
            int mid = lo + ((hi - lo) >> 1);
            if(nums[mid] == target) 
                return true;
            if(nums[mid] < nums[hi]){  
                if(nums[hi] < target || target < nums[mid]){  
                    hi = mid - 1;
                }else{
                    lo = mid + 1;
                }
            }else if(nums[mid] > nums[hi]){
                if(nums[mid] < target || target < nums[lo]){ 
                   lo = mid + 1;
                }else{
                    hi = mid - 1;
                }
            }else{
                 while(lo <= hi && nums[lo] == nums[mid]) lo++;
                 while(lo <= hi && nums[hi] == nums[mid]) hi--;
            }
                
        }
        
        return false; 
    }

34. Find First and Last Position of Element in Sorted Array

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

思路:
先判断两个端点
利用二分法查找中间位置,然后通过比较在哪个半区
下标的周围元素若一样则移动到不同元素处
注意,在相邻位置(8,8,10,10)出现target=9时需要break条件

 public int[] searchRange(int[] nums, int target) {
         if(nums == null || nums.length < 1)
	        	return new int[]{-1, -1};
	        int lo = 0;
	        int hi = nums.length - 1;
	        int[] res = new int[2];
	        if(target == nums[lo]){
	        	res[0] = 0;
	        	int i = 0;
	        	while(i <= hi){
	        		if(nums[i] == nums[0]){
	        			i++;
	        		}else {
						break;
					}
	        	}
	        	res[1] = i - 1;
	        	return res;
	        }
	        if(target == nums[hi]){
	        	res[1] = hi;
	        	int i = hi;
	        	while(i >= 0){
	        		if(nums[i] == nums[hi]){
	        			i--;
	        		}else {
						break;
					}
	        	}
	        	res[0] = i + 1;
	        	return res;
	        }	
	        while(lo <= hi){
	        	int mid = lo + ((hi - lo) >> 1);
	        	if(nums[mid] < target && target < nums[hi] ){
	        		while(mid + 1 <= hi && nums[mid] == nums[mid + 1]) mid++;
	        		while(hi - 1 >= mid && nums[hi] == nums[hi - 1]) hi--;
	        		lo = mid;
	        		if(mid + 1 == hi){
	        			res[0] = -1;
						res[1] = -1;
						break;
	        		}	
	        	}else if(nums[mid] > target && target > nums[lo]){
	        		while(mid - 1 >= lo && nums[mid] == nums[mid - 1]) mid--;
	        		while(lo + 1 <= mid && nums[lo] == nums[lo + 1]) lo++;
	        		hi = mid;
	        		if(mid - 1 == lo){
	        			res[0] = -1;
						res[1] = -1;
						break;
	        		}
				}else if(target == nums[mid]){
					while(nums[mid] == nums[mid + 1] && mid < hi) mid++;
					res[1] = mid;
					while(nums[mid] == nums[mid - 1] && mid > lo ) mid--;
					res[0] = mid;
					break;
				}else {
					res[0] = -1;
					res[1] = -1;
					break;
				}
	        }
	        return res;
    }

通用结构

Subsets : https://leetcode.com/problems/subsets/

public List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, 0);
    return list;
}

private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
    list.add(new ArrayList<>(tempList));
    for(int i = start; i < nums.length; i++){
        tempList.add(nums[i]);
        backtrack(list, tempList, nums, i + 1);
        tempList.remove(tempList.size() - 1);
    }
}
Subsets II (contains duplicates) : https://leetcode.com/problems/subsets-ii/

public List<List<Integer>> subsetsWithDup(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, 0);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int start){
    list.add(new ArrayList<>(tempList));
    for(int i = start; i < nums.length; i++){
        if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates
        tempList.add(nums[i]);
        backtrack(list, tempList, nums, i + 1);
        tempList.remove(tempList.size() - 1);
    }
} 
Permutations : https://leetcode.com/problems/permutations/

public List<List<Integer>> permute(int[] nums) {
   List<List<Integer>> list = new ArrayList<>();
   // Arrays.sort(nums); // not necessary
   backtrack(list, new ArrayList<>(), nums);
   return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
   if(tempList.size() == nums.length){
      list.add(new ArrayList<>(tempList));
   } else{
      for(int i = 0; i < nums.length; i++){ 
         if(tempList.contains(nums[i])) continue; // element already exists, skip
         tempList.add(nums[i]);
         backtrack(list, tempList, nums);
         tempList.remove(tempList.size() - 1);
      }
   }
} 
Permutations II (contains duplicates) : https://leetcode.com/problems/permutations-ii/

public List<List<Integer>> permuteUnique(int[] nums) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, boolean [] used){
    if(tempList.size() == nums.length){
        list.add(new ArrayList<>(tempList));
    } else{
        for(int i = 0; i < nums.length; i++){
            if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;
            used[i] = true; 
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, used);
            used[i] = false; 
            tempList.remove(tempList.size() - 1);
        }
    }
}
Combination Sum : https://leetcode.com/problems/combination-sum/

public List<List<Integer>> combinationSum(int[] nums, int target) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, target, 0);
    return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
    if(remain < 0) return;
    else if(remain == 0) list.add(new ArrayList<>(tempList));
    else{ 
        for(int i = start; i < nums.length; i++){
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, remain - nums[i], i); // not i + 1 because we can reuse same elements
            tempList.remove(tempList.size() - 1);
        }
    }
}
Combination Sum II (can't reuse same element) : https://leetcode.com/problems/combination-sum-ii/

public List<List<Integer>> combinationSum2(int[] nums, int target) {
    List<List<Integer>> list = new ArrayList<>();
    Arrays.sort(nums);
    backtrack(list, new ArrayList<>(), nums, target, 0);
    return list;
    
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
    if(remain < 0) return;
    else if(remain == 0) list.add(new ArrayList<>(tempList));
    else{
        for(int i = start; i < nums.length; i++){
            if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, remain - nums[i], i + 1);
            tempList.remove(tempList.size() - 1); 
        }
    }
} 
Palindrome Partitioning : https://leetcode.com/problems/palindrome-partitioning/

public List<List<String>> partition(String s) {
   List<List<String>> list = new ArrayList<>();
   backtrack(list, new ArrayList<>(), s, 0);
   return list;
}

public void backtrack(List<List<String>> list, List<String> tempList, String s, int start){
   if(start == s.length())
      list.add(new ArrayList<>(tempList));
   else{
      for(int i = start; i < s.length(); i++){
         if(isPalindrome(s, start, i)){
            tempList.add(s.substring(start, i + 1));
            backtrack(list, tempList, s, i + 1);
            tempList.remove(tempList.size() - 1);
         }
      }
   }
}

public boolean isPalindrome(String s, int low, int high){
   while(low < high)
      if(s.charAt(low++) != s.charAt(high--)) return false;
   return true;
} 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值