链表的题里面,快慢指针、双指针用得很多。
2.1 Write code to remove duplicates from an unsorted linked list.
FOLLOW UP
How would you solve this problem if a temporary buffer is not allowed?
2.2 Implement an algorithm to find the kth to last element of a singly linked list.
2.3 Implement an algorithm to delete a node in the middle of a singly linked list, given only access to that node.
2.4 Write code to partition a linked list around a value x, such that all nodes less than x come before alt nodes greater than or equal to x.
Leetcode上有,点此。
2.5 You have two numbers represented by a linked list, where each node contains a single digit. The digits are stored in reverse order, such that the 1 's digit is at the head of the list. Write a function that adds the two numbers and returns the sum as a linked list.
Leetcode上有,点此。
FOLLOW UP
Suppose the digits are stored in forward order. Repeat the above problem.
reverse之后求后然后再reverse结果,careercup上的做法更inefficient。
2.6 Given a circular linked list, implement an algorithm which returns the node at the beginning of the loop.
Leetcode上有,点此。
2.7 Implement a function to check if a linked list is a palindrome,
naive的方法就是把list reverse一下,然后和原串比较。
更好的方法是用stack,比较前半部分还是很巧妙的。stack用来reverse也是比较直观的。注意奇偶长度的list。
递归的方法理解起来更难些。传递指针的指针,使得递归调用后,指针move到对应的镜像位置上了。这一点和Leetcode上Convert Sorted List to Binary Search Tree类似。
1 struct ListNode { 2 int val; 3 ListNode* next; 4 ListNode(int v) : val(v), next(NULL) {} 5 }; 6 7 class XList { 8 public: 9 XList(int n) { 10 srand(time(NULL)); 11 head = NULL; 12 for (int i = 0; i < n; ++i) { 13 ListNode* next = new ListNode(rand() % 1000); 14 next->next = head; 15 head = next; 16 } 17 len = n; 18 } 19 20 XList(XList ©) { 21 //cout << "copy construct" << endl; 22 len = copy.size(); 23 if (len == 0) return; 24 head = new ListNode(copy.head->val); 25 ListNode *p = copy.head->next, * tail = head; 26 27 while (p != NULL) { 28 tail->next = new ListNode(p->val); 29 tail = tail->next; 30 p = p->next; 31 } 32 } 33 34 ~XList() { 35 ListNode *tmp = NULL; 36 37 while (head != NULL) { 38 tmp = head->next; 39 delete head; 40 head = tmp; 41 } 42 } 43 44 // 2.1(1) 45 void removeDups() { 46 if (head == NULL) return; 47 map<int, bool> existed; 48 ListNode* p = head, *pre = NULL; 49 while (p != NULL) { 50 if (existed[p->val]) { 51 pre->next = p->next; 52 len--; 53 delete p; 54 p = pre->next; 55 } else { 56 pre = p; 57 existed[p->val] = true; 58 p = p->next; 59 } 60 } 61 } 62 63 //2.1(2) 64 void removeDups2() { 65 ListNode *p = head; 66 67 while (p != NULL) { 68 ListNode *next = p; 69 while (next->next) { 70 if (next->next->val == p->val) { 71 ListNode *tmp = next->next; 72 len--; 73 delete next->next; 74 next->next = tmp->next; 75 } else { 76 next = next->next; // only move to next in the 'else' block 77 } 78 } 79 p = p->next; 80 } 81 } 82 83 // 2.2(1) 84 ListNode* findKthToLast(int k) { 85 if (head == NULL) return NULL; 86 if (k <= 0) return NULL; // more efficient 87 ListNode *fast = head, *slow = head; 88 int i = 0; 89 for (; i < k && fast; ++i) { 90 fast = fast->next; 91 } 92 if (i < k) return NULL; 93 while (fast) { 94 slow = slow->next; 95 fast = fast->next; 96 } 97 return slow; 98 } 99 100 //2.2(2) 101 ListNode* findKthToLast2(int k) { 102 return recursiveFindKthToLast(head, k); 103 } 104 105 //2.2(2) 106 ListNode* recursiveFindKthToLast(ListNode *h, int &k) { 107 if (h == NULL) { 108 return NULL; 109 } 110 111 // should go to the end 112 ListNode *ret = recursiveFindKthToLast(h->next, k); 113 k--; 114 if (k == 0) return h; 115 return ret; 116 } 117 118 // 2.3 119 bool deleteNode(ListNode* node) { 120 if (node == NULL || node->next == NULL) return false; // in the middle, head is also ok, because we don't delete node itself 121 122 ListNode *next = node->next; 123 node->val = next->val; 124 node->next = next->next; 125 len--; 126 delete next; 127 return true; 128 } 129 130 // 2.4 131 void partition(int x) { 132 if (head == NULL) return; 133 ListNode less(0), greater(0); 134 ListNode* p = head, *p1 = &less, *p2 = &greater; 135 136 while (p) { 137 if (p->val < x) { 138 p1->next = p; 139 p1 = p1->next; 140 } else { 141 p2->next = p; 142 p2 = p2->next; 143 } 144 p = p->next; 145 } 146 147 p1->next = greater.next; 148 head = less.next; 149 } 150 151 // 2.7(1) 152 bool isPalindrome() { 153 if (head == NULL) return true; 154 stack<ListNode*> st; 155 ListNode *fast = head, *slow = head; 156 while (fast && fast->next) { 157 st.push(slow); 158 slow = slow->next; 159 fast = fast->next->next; 160 } 161 162 if (fast) slow = slow->next; // fast->next = null, odd number, skip the middle one 163 164 while (slow) { 165 if (slow->val != st.top()->val) return false; 166 slow = slow->next; 167 st.pop(); 168 } 169 170 return true; 171 } 172 173 // 2.7(2) 174 bool isPalindrome2() { 175 ListNode* h = head; 176 return recursiveIsPalindrome(h, len); 177 } 178 179 bool recursiveIsPalindrome(ListNode* &h, int l) { // note that h is passed by reference 180 if (l <= 0) return true; 181 if (l == 1) { 182 h = h->next; // move, when odd 183 return true; 184 } 185 if (h == NULL) return true; 186 int v1 = h->val; 187 h = h->next; 188 if (!recursiveIsPalindrome(h, l - 2)) return false; 189 int v2 = h->val; 190 h = h->next; 191 cout << v1 << " vs. " << v2 << endl; 192 return v1 == v2; 193 } 194 195 void print() const { 196 ListNode *p = head; 197 while (p != NULL) { 198 cout << p->val << "->"; 199 p = p->next; 200 } 201 cout << "NULL(len: " << len << ")" << endl; 202 } 203 204 int size() const { 205 return len; 206 } 207 208 void insert(int v) { 209 len++; 210 ListNode *node = new ListNode(v); 211 node->next = head; 212 head = node; 213 } 214 private: 215 ListNode *head; 216 int len; 217 };