1. 删除排序数组中的重复项
要求:给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
思路:1. 在不改变当前数组的情况下,将当前数组的下表往后移动
2. 在原有的数组不变更的情况下,找到当前的不重复的值赋值给当前下标的值
public static int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int len = 0;
for(int i=0;i<nums.length;){
while (i<nums.length -1 &&nums[i] == nums[i+1] ){
i++;
}
nums[len++] = nums[i++];
}
return len;
}
2. 旋转数组
要求:给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 要求使用空间复杂度为 O(1) 的原地算法。
方案一:一个一个替换,比较繁琐
public void rotate(int[] nums, int k){
k = k % nums.length;
for(int i=0;i<k;i++){
int fir = nums[nums.length - 1];
//从倒数第二个元素开始移动
for (int j = nums.length - 2; j >= 0; j--) {
nums[j + 1] = nums[j];
}
//每次的第一个元素都是移动前的最后一个
nums[0] = fir;
}
}
方案二:将旧数组的元素按照替换后的位置重新赋给新数组
public void rotateArray(int[] nums, int k) {
k = k % nums.length;
int[] nnums = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
int num = (i + k) % nums.length;
nnums[num] = nums[i];
}
for (int i = 0; i < nnums.length; i++) {
nums[i] = nnums[i];
}
}
方案三:自组旋转
public void rotate(int[] nums, int k) { if(nums==null || nums.length==0){ return ; } if(nums.length==1){ return ; } k=k%nums.length; reverse(nums); reverse(nums,0,k-1); reverse(nums,k,nums.length-1); } public void reverse(int[] arr,int begin,int end){ int half=(end-begin+1)/2; int tar; for(int i=0;i<half;i++){ tar=arr[begin]; arr[begin]=arr[end]; arr[end]=tar; begin++; end--; }
}
public void reverse(int[] arr){
reverse(arr,0,arr.length-1);
}
3. 合并两个有序数组
要求:给定两个排序整数数组nums1和nums2,将nums2合并为一个排序数组nums1。
nums1和nums2中初始化的元素数量分别为m和n。
您可以假设nums1有足够的空间(大小大于或等于m + n)来容纳nums2中的其他元素。
思路:混合插入有序数组,由于两个数组都是有序的,所以只要按顺序比较大小即可。题目中说了nums1数组有足够大的空间,说明我们不用resize数组,又给了我们m和n,那就知道了混合之后的数组大小,这样我们就从nums1和nums2数组的末尾开始一个一个比较,把较大的数,按顺序从后往前加入混合之后的数组末尾。
// 备注:当前代码编译通过不了主动扩展,因为当前的数组无法
public static int[] mergeArray(int nums1[],int m,int nums2[],int n){
int i = m-1,j = n-1,k = m+n-1;
while (i>=0 && j>=0){
nums1[k--] = nums1[i]>nums2[j]?nums1[i--]:nums2[j--];
}
while (j>=0){
nums1[k--] = nums2[j--];
}
return nums1;
}
对上面的代码进行整合:
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m-1, j = n-1, k = m+n-1;
while(j>=0){
nums1[k--] = i >= 0 && nums1[i]>nums2[j] ? nums1[i--] : nums2[j--];
}
}
4. 两两交换链表中的结点
要求:给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
方案一思路:
- 申请一个空结点
- 使用空结点作为当前的临时替换结点
public Node swapPairs(Node head) {
Node tmp =new Node(0); //申请一个空的节点
tmp.next = head; //让链表的头节点指向那个空节点的下一个节点
Node temp = tmp; //把这个空节点保存下来,用这个变量去完成交换
while(head != null && head.next !=null){
temp.next = head.next;
head.next = temp.next.next;
temp.next.next = head;
temp = temp.next.next; //当上面交换完了后,temp向后移两个节点。
head = temp.next;
}
return tmp.next; //返回空节点之后已经交换完了的链表
}
方法二:把节点一个一个取出来,两个两个一交换,用递归实现,
public Node swapPairs2(Node head) {
if(head == null || head.next == null){
return head;
}
Node res = head.next; //找到交换节点的下一个
Node temp = swapPairs(head.next.next); //需要移动头部
res.next = head; //交换
head.next = temp; //头部移动到下一组
return res; //返回空节点之后已经交换完了的链表
}
5. 三数之和
要求:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
方法一:暴力解法
遍历选取任意三个元素相加是否为零,利用Set去重。
public List<List<Integer>> threeSum(int[] nums) {
Set<List<Integer>> Set = new HashSet<List<Integer>>();
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++)
for(int j=i+1;j<nums.length-1;j++)
for(int k=j+1;k<nums.length;k++)
if(nums[i]+nums[j]+nums[k]==0)Set.add(Arrays.asList(nums[i],nums[j],nums[k]);
return new ArrayList<List<Integer>>(Set);
}
方案二: 双指针法
思路:
- 排序
- 固定一个值,找另外二个值它们和等于
0,如何找另外两个值,用的是双指针!
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
List<List<Integer>> res = new LinkedList<>();
for(int i=0;i<n;i++){
if(i>0 && nums[i] == nums[i-1]){
continue;
}
int left = i+1;
int right = n-1;
while (left < right){
int tmp = nums[i] + nums[left] + nums[right];
if(tmp == 0){
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) left += 1;
while (left < right && nums[right] == nums[right - 1]) right -= 1;
left += 1;
right -= 1;
}else if(tmp > 0){
right -= 1;
}else {
left += 1;
}
}
}
return res;
}