定义链表节点结构:
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
这是一个简单的问题,仅测试你操作列表的结点指针的能力。由于输入的列表已排序,因此我们可以通过将结点的值与它之后的结点进行比较来确定它是否为重复结点。如果它是重复的,我们更改当前结点的 next 指针,以便它跳过下一个结点并直接指向下一个结点之后的结点。
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while (current != null && current.next != null) {
if (current.next.val == current.val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
无序单链表的去重:
思路:思路: 通过双重循环直接在链表上执行删除操作。外层循环用一个指针从第一个节点开始遍历整个链表,然后内层循环用另一个指针遍历其余节点,将与外层循环遍历到的指针所指节点的数据域相同的节点删除(删除的是内层循环的节点)。
public ListNode deleteDuplicates2(ListNode head) {
//排除空表和单节点情况
if (head == null || head.next == null) {
return head;
}
ListNode outerCur = head;//用于外层循环,指向链表第一个节点
ListNode innerCur = null;//内层循环用来遍历outerCur后面的节点
//一旦涉及节点删除,那么就要找到该节点的前驱节点
ListNode innerPre = null;//innerCur的前驱节点
for (; outerCur != null; outerCur = outerCur.next) {
for (innerCur = outerCur.next, innerPre = outerCur; innerCur != null; ) {
//找到重复的节点并删除
if (outerCur.val == innerCur.val) {
innerPre.next = innerCur.next;
innerCur = innerCur.next;
} else {
innerPre = innerCur;
innerCur = innerCur.next;
}
}
}
return head;
}
单链表的反转:
思路:所谓的单链表反转,就是把每个节点的指针域由原来的指向下一个节点变为指向其前一个节点。 但由于单链表没有指向前一个节点的指针域,因此我们需要增加一个指向前一个节点的指针pre,用于存储每一个节点的前一个节点。此外,还需要定义一个保存当前节点的指针cur,以及下一个节点的next。定义好这三个指针后,遍历单链表,将当前节点的指针域指向前一个节点,之后将定义三个指针往后移动, 直至遍历到最后一个节点停止。
链表反转过程
public ListNode reverseListNode(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode preNode = null; //当前节点的前一个节点
ListNode curNode = head; //当前节点
ListNode nextNode = null;//当前加诶点的后一个节点
while (curNode!=null) {
nextNode = curNode.next; //存储当前节点的下一个节点
curNode.next = preNode; //当前节点的下节点指向前节点
preNode = curNode; //前节点后移
curNode = nextNode; //当前节点也后移
}
return preNode;
}
完整版代码:
package leetcode;
/**
* 83. 删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
* @author root
*
*/
public class C83 {
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public ListNode addListNode(int[] nums) {
ListNode headNode = null, tailNode=null;
for (int i : nums) {
if (tailNode == null) {
ListNode dataNode = new ListNode(i);
headNode = dataNode;
tailNode = headNode;
tailNode.next = null;
}else {
ListNode dataNode = new ListNode(i);
tailNode.next = dataNode;
tailNode = tailNode.next;
}
}
return headNode;
}
public ListNode findData(ListNode head, int data) {
if (head==null) {
return null;
}
int index = -1;
while (head!=null) {
if (head.val == data) {
return head;
}
head = head.next;
}
return null;
}
/**
* 思路:所谓的单链表反转,就是把每个节点的指针域由原来的指向下一个节点变为指向其前一个节点。
* 但由于单链表没有指向前一个节点的指针域,因此我们需要增加一个指向前一个节点的指针pre,
* 用于存储每一个节点的前一个节点。此外,还需要定义一个保存当前节点的指针cur,以及下一个节点的next。
* 定义好这三个指针后,遍历单链表,将当前节点的指针域指向前一个节点,之后将定义三个指针往后移动,
* 直至遍历到最后一个节点停止。
* 时间复杂度:O(n)
* @param head
* @return
*/
public ListNode reverseListNode(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode preNode = null; //当前节点的前一个节点
ListNode curNode = head; //当前节点
ListNode nextNode = null;//当前加诶点的后一个节点
while (curNode!=null) {
nextNode = curNode.next; //存储当前节点的下一个节点
curNode.next = preNode; //当前节点的下节点指向前节点
preNode = curNode; //前节点后移
curNode = nextNode; //当前节点也后移
}
return preNode;
}
/**
* 针对排序链表进行去重,无序链表会出错
* 思路:这是一个简单的问题,仅测试你操作列表的结点指针的能力。由于输入的列表已排序,
* 因此我们可以通过将结点的值与它之后的结点进行比较来确定它是否为重复结点。如果它是重复的,
* 我们更改当前结点的 next 指针,以便它跳过下一个结点并直接指向下一个结点之后的结点。
* 时间复杂度O(n)
* @param head
* @return
*/
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while (current != null && current.next != null) {
if (current.next.val == current.val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
/**
* 针对无序单链表进行元素去重
* 时间复杂度O(n^2)
* 思路: 通过双重循环直接在链表上执行删除操作。外层循环用一个指针从第一个节点开始遍历整个链表,
* 然后内层循环用另一个指针遍历其余节点,将与外层循环遍历到的指针所指节点的数据域相同的节点删除
* (删除的是内层循环的节点)。
* @param head
* @return
*/
public ListNode deleteDuplicates2(ListNode head) {
//排除空表和单节点情况
if (head == null || head.next == null) {
return head;
}
ListNode outerCur = head;//用于外层循环,指向链表第一个节点
ListNode innerCur = null;//内层循环用来遍历outerCur后面的节点
//一旦涉及节点删除,那么就要找到该节点的前驱节点
ListNode innerPre = null;//innerCur的前驱节点
for (; outerCur != null; outerCur = outerCur.next) {
for (innerCur = outerCur.next, innerPre = outerCur; innerCur != null; ) {
//找到重复的节点并删除
if (outerCur.val == innerCur.val) {
innerPre.next = innerCur.next;
innerCur = innerCur.next;
} else {
innerPre = innerCur;
innerCur = innerCur.next;
}
}
}
return head;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
C83 c83 = new C83();
int[] nums = {1,1,2,3,6,5,4,4,9,7,3,9,9,8,7,7,7,7};
ListNode headNode = c83.addListNode(nums);
ListNode tmpNode = headNode;
while (tmpNode!=null) {
System.out.println(tmpNode.val);
tmpNode = tmpNode.next;
}
System.out.println("===========deleteDuplicates============");
headNode = c83.deleteDuplicates2(headNode);
tmpNode = headNode;
while (tmpNode!=null) {
System.out.println(tmpNode.val);
tmpNode = tmpNode.next;
}
System.out.println("===========reverseListNode============");
headNode = c83.reverseListNode(headNode);
tmpNode = headNode;
while (tmpNode!=null) {
System.out.println(tmpNode.val);
tmpNode = tmpNode.next;
}
}
}