一、两数之和
1.1题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
1.2思路
这道题我的思路是遍历数组,通过for循环对数组进行遍历,在这个for循环中内嵌一个for循环对数组遍历,内部for循环中判断当前索引值与外部循环当前索引值相加与目标值比较,判断是否相等,若相等,则返回一个数组,数组内元素就是两个for循环当前的索引,若不相等,则继续遍历,数组遍历完后仍未找到,则返回一个空数组。
1.3 代码
public int[] twoSum(int[] nums, int target) { int n = nums.length; for (int i = 0;i < n;i++) { for(int j = i + 1;j < n;j++) { if(nums[i] + nums[j] == target) { return new int[]{i,j}; } } } return new int[]{0}; }
二、移动零
2.1题目描述
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
2.2思路
我的思路是遍历数组,定义左右指针,初始时两个指针left、right均指向数组0索引处,当right小于数组长度时,开始循环,在循环内判断right索引处的值是否等于0,若等于0则与left索引处的值进行交换,交换后left自增,right也自增,若不等于0,则只需right自增,依次遍历,得出最终数组。
2.3代码
public void moveZeroes(int[] nums) { int n = nums.length; int left = 0; int right = 0; while (right < n) { if(nums[right] != 0) { swap(nums,left,right); left++; } right++; } } public void swap(int[] nums,int left,int right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; }
三、相交链表
3.1题目描述
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须保持其原始结构 。
3.12思路
这道题可以通过利用Set集合的特性进行求解,分析题目可以看出是要我们在两个单链表中找出两个链表开始相交时的节点,那么我们就可以先将一个链表存入Set集合,再遍历第二个链表利用Set集合的contains()方法判断当前集合中是否包含第二个集合的节点,若包含,则直接返回当前节点,不包含则继续遍历,遍历完仍未找到,则返回null。
3.3代码
public ListNode getIntersectionNode(ListNode headA, ListNode headB) { Set<ListNode> set = new HashSet<ListNode>(); ListNode temp = headA; while (temp != null) { set.add(temp); temp = temp.next; } temp = headB; while (temp != null) { if(set.contains(temp)) { return temp; } temp = temp.next; } return null; }
四、反转链表
4.1题目描述
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
- 输入:head = [1,2,3,4,5]
- 输出:[5,4,3,2,1]
4.2思路一
链表反转后顺序跟之前是完全相反的,创建一个空节点n1,初始让n1.next指向null,表示n1是最后一个节点,创建一个节点指针p,p初始指向链表的头,开始遍历链表,当p不为空时,创建新节点,新节点的值为当前节点p的值,新节点的下一个节点为n1,再将这个新节点赋给n1,遍历下一个节点,当遍历完成后,返回n1,此时n1就是新链表的头节点。
4.3代码
public ListNode reverseList(ListNode head) { if (head == null) { return null; } ListNode n1 = null; ListNode p = head; while (p != null) { n1 = new ListNode(p.val,n1); p = p.next; } return n1; }
这种方式在每次循环时都需要创建一个新的节点,效率太低。
4.4思路二
第二种方式是将这个链表进行重新构造,在这个链表的基础上进行头删,将头删拿到的节点作为新节点进行头插形成新的链表,具体通过创建一个外部类,外部类中有头插和头删得到节点值的方法,创建两个外部类的对象,进行上面的思路操作,返回新链表的头结点即可。
4.5代码
public ListNode reverseList(ListNode head) { List list1 = new List(head); List list2 = new List(null); while (true) { ListNode first = list1.removeFirst(); if (first == null) { break; } list2.addFirst(first); } return list2.head; } static class List { ListNode head; public List(ListNode head) { this.head = head; } public void addFirst(ListNode first) { first.next = head; head = first; } public ListNode removeFirst() { ListNode first = head; if (first != null) { head = first.next; } return first; } }
4.6思路三
第三种方式是用递归,在反转链表方法中再次调用反转链表方法参数为当前头结点的下一个节点,返回前,将头结点的下一个的下一个指向头head,头的下一个指向null,最后返回最后一个节点。
4.7代码
public ListNode reverseList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode last = reverseList(head.next); head.next.next = head; head.next = null; return last; }