88.合并两个有序数组
思路:(双指针)
用两个指针分别指向nums1和nums2,每次对比两个指针元素的大小,小的放到nums3(结果暂存在这个数组)中,nums3的指针和相对小的元素所在的数组的指针后移,直到某个指针到达某个数组的最后一个非0元素结束。
代码:
public void merge(int[] nums1, int m, int[] nums2, int n) {
if(m==0){
for(int i=0;i<n;i++){
nums1[i]=nums2[i];
}
}else if(m!=0&&n!=0){
int nums3[]=new int[m+n];
int i1=0,i2=0,i3=0;
while(i1<m&&i2<n){
if(nums1[i1]<=nums2[i2]){
nums3[i3++]=nums1[i1++];
}else{
nums3[i3++]=nums2[i2++];
}
}
if(i1==m){
for(int i=i2;i<n;i++)
nums3[i3++]=nums2[i2++];
}else if(i2==n){
for(int i=i1;i<m;i++)
nums3[i3++]=nums1[i1++];
}
for(int i=0;i<m+n;i++){
nums1[i]=nums3[i];
}
}
}
思路:(方法论)
直接调用Arrays里面的sort方法(效率低,上面那个0ms,就是空间占用大)
代码:
public void merge(int[] nums1, int m, int[] nums2, int n) {
int nn=0;
for(int i=m;i<m+n;i++){
nums1[i]=nums2[nn++];
}
Arrays.sort(nums1);
}
思路:(逆向双指针)
和第一个方法类似,但是是从两个数组的最后一个元素进行比较,比较的结果填到nums1后面的数(nums1总长度m+n,从最后一个开始填充)。只是把那个nums3的指针放到nums1的最后一个元素。具体填充方法:两个数组最后一个非0数字对比,如果是nums1大,则把当前这个下标的元素放到最后一位非0位置,然后将原来的那个位置置为0,直到nums1后面的指针到了一个非0的位置。
代码:
public void merge(int[] nums1, int m, int[] nums2, int n) {
if(m==0){
int i=0;
for(int num:nums2){
nums1[i++]=num;
}
}else if(m!=0&&n!=0){
int rear=m+n-1;//0数组尾部指针
int rear1=m-1,rear2=n-1;//nums1和2数组尾部指针
while(rear>=0){
if(rear1<0){
nums1[rear]=nums2[rear2];
rear2--;
rear--;
}else if(rear2<0){
break;
}else{
if(nums1[rear1]>nums2[rear2]){
nums1[rear]=nums1[rear1];
rear--;
nums1[rear1]=0;
rear1--;
}else{
nums1[rear]=nums2[rear2];
rear--;
rear2--;
}
}
}
}
}
160.相交链表
思路:(HashSet)
利用hashset每个元素只能存一次的性质,add方法失败的话就表示有相同的两个节点,返回值就是相交节点,但是这种方法效率低
代码:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set=new HashSet<>();
if(headA==null||headB==null)
return null;
while(headA!=null||headB!=null){
if(headA!=null&&!set.add(headA)){
return headA;
}
if(headB!=null&&!set.add(headB)){
return headB;
}
if(headA!=null)headA=headA.next;
if(headB!=null)headB=headB.next;
}
return null;
}
思路:(双指针)(妙啊)
两个链表长度的和为m+n,所以设置A链表的指针为iA,B链表的指针为iB,假设两个链表相交,如果相交节点前走过的节点数相同,那肯定会在相交节点相遇;如果A的长度不等于B的长度,那么就让iA走完A链表后去走B链表,让iB走完后去走A链表的路,然后肯定会在相交节点相遇(因为相交以后所有的结点都是A和B共有的,所以数量肯定一样)如果假设两个链表不相交,就都会在遍历完两个链表后返回null,所以最坏的情况是走了m+n次,但是指针数量为常数个,所以空间复杂度O(1)
代码:
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null||headB==null)
return null;
ListNode iA=headA;
ListNode iB=headB;
while(iA!=iB){
iA=iA==null?headB:iA.next;
iB=iB==null?headA:iB.next;
}
return iA;
}
415.字符串相加
思路:(双指针)
设计两个指针分别指向两个字符串的最后一个元素,new一个StringBuffer可以用append方法将每次运算得出来的结果插到尾部,最后将结果反过来就好了。主要是判断条件那里,要判断什么时候应该停掉指针,应该要运算到最长的字符串最后一位,且判断有没有进位,有进位还要继续运算。
代码:
class Solution {
public String addStrings(String num1, String num2) {
int i = num1.length() - 1, j = num2.length() - 1, add = 0;
StringBuffer ans = new StringBuffer();
while (i >= 0 || j >= 0 || add != 0) {
int x = i >= 0 ? num1.charAt(i) - '0' : 0;
int y = j >= 0 ? num2.charAt(j) - '0' : 0;
int result = x + y + add;
ans.append(result % 10);
add = result / 10;
i--;
j--;
}
// 计算完以后的答案需要翻转过来
ans.reverse();
return ans.toString();
}
}
704.二分查找
思路:(二分)
需要注意的是while循环的条件以及target小于和大于nums[mid]的时候,left和right应该怎么移动
代码:
public int search(int[] nums, int target) {
if(target>nums[nums.length-1]||target<nums[0])
return -1;
else if(target==nums[0])
return 0;
else if(target==nums[nums.length-1])
return nums.length-1;
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=(right+left)>>1;
if(target==nums[mid]){
return mid;
}else if(target<nums[mid]){
right=mid-1;
}else if(target>nums[mid]){
left=mid+1;
}
}
return -1;
}
83.删除排序链表中的重复项
思路:(双指针)
就对比前后两个指针的值,如果相等,左指针的next指向右指针的next。如果不相等,将两个指针后移。结果返回head是因为头结点没有被改变。
代码:
public ListNode del(ListNode head){
ListNode last=null;
ListNode node=head;
while(node!=null){
if(last==null){
last=node;
node=node.next;
}else{
if(last.val==node.val){
last.next=node.next;
}else{
last=last.next;
}
node=node.next;
}
}
return head;
}
做个第一周的小总结吧,额..确实刷的都是些简单题,而且一开始做题根本就想不太出来代码要怎么写,不会用HashMap,HashSet或者是Queue等等类型的数据结构,但是通过边刷题,边背/理解一些八股文,就很快能够掌握怎么使用这些框架集合了。
总的来说吧,就是别懒,该刷得刷,该背得背,确实没思路的题看别人的题解,然后照着别人的思路还原出来代码,有时间多回头再刷几遍就完事了。万事开头难,加油,奥利给!