<span style="font-family: 'microsoft yahei';font-size:18px; line-height: 26px;">先將其中一個鏈表的鏈頭按到另一個鏈表的尾部,如果他們有交集則會構成一個環,題目等價於找鏈表中的環的起始結點。找到後將鏈表還原。</span>
一.兩個長鏈表求交點(考慮環)
<span style="font-size: 48px;"> </span><span style="font-size:18px;"> public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode ta; // 用於記錄headA鏈表的尾結點
ListNode ha = headA;
// 第一步、找到headA的尾結點
while (ha.next != null) {
ha = ha.next;
}
ta = ha; // 記錄鏈表headA的尾結點
// 第二步、將headB接到ta後面
ta.next = headB;
// 第三步、判斷是否存在環
// 判斷鏈表是否存在環,辦法爲:
// 設置兩個指針(fast, slow),初始值都指向頭,slow每次前進一步,fast每次前進二步,
// 如果鏈表存在環,則fast必定先進入環,而slow後進入環,兩個指針必定相遇。
// (當然,fast先行頭到尾部爲NULL,則爲無環鏈表)程序如下:
ListNode fast = headA; // 每次前進一步
ListNode slow = headA; // 每次前進二步
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) { // 如果相遇了就退出來
break;
}
}
// 沒有環的情況
if (fast == null || fast.next == null) {
ta.next = null; // 解開拼接好的鏈表
return null;
}
// 有環的情況
// 找到環的入口點
// 當fast若與slow相遇時,slow肯定沒有走遍歷完鏈表,而fast已經在環內循環了n圈(1<=n)。
// 假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長爲r,則:
//
// 2s = s + nr
// s= nr
//
// 設整個鏈表長L,入口環與相遇點距離爲x,起點到環入口點的距離爲a。
// a + x = nr
// a + x = (n – 1)r +r = (n-1)r + L - a
// a = (n-1)r + (L – a – x)
//
// (L – a – x)爲相遇點到環入口點的距離,由此可知,從鏈表頭到環入口點等於(n-1)循環內環+相遇點到環入口點,
// 於是我們從鏈表頭、與相遇點分別設一個指針,每次各走一步,兩個指針必定相遇,且相遇第一點爲環入口點。
slow = headA;
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}
ta.next = null;
return slow;
}
}</span>
二。反轉單鏈表,反轉單鏈表的部分區間
ublic class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
1
2
3
4
5
算法實現類
public class Solution {
public ListNode reverseList(ListNode head) {
// 頭結點
ListNode root = new ListNode(0);
ListNode nextNode;
while (head != null) {
nextNode = head.next;
head.next = root.next;
root.next = head;
head = nextNode;
}
return root.next;
}
}
三。刪除原排序數組內重複次數超過三次的數字(不開輔助空間)
public class Solution {
/**
* @param A: a array of integers
* @return : return an integer
*/
public int removeDuplicates(int[] nums) {
// write your code here
int i = 0;
int numsLen = nums.length;
while(i<numsLen-1){
if(nums[i]==nums[i+1]){
for(int j=i+1;j<numsLen-1;j++)
nums[j]=nums[j+1];
numsLen-=1;
}else
i+=1;
}
return numsLen;
}
}
四。
當我們加上一個正數時,和會增加;當我們加上一個負數時,和會減少。如果當前得到的和是個負數,那麼這個和在接下來的累加中應該拋棄並重新清零,不然的話這個負數將會減少接下來的和。實現:
複製代碼
//copyright@ July 2010/10/18
//updated,2011.05.25.
#include <iostream.h>
int maxSum(int* a, int n)
{
int sum=0;
//其實要處理全是負數的情況,很簡單,如稍後下面第3點所見,直接把這句改成:"int sum=a[0]"即可
//也可以不改,當全是負數的情況,直接返回0,也不見得不行。
int b=0;
for(int i=0; i<n; i++)
{
if(b<0) //...
b=a[i];
else
b+=a[i];
if(sum<b)
sum=b;
}
return sum;
}
int main()
{
int a[10]={1, -2, 3, 10, -4, 7, 2, -5};
//int a[]={-1,-2,-3,-4}; //測試全是負數的用例
cout<<maxSum(a,8)<<endl;
return 0;
}
/*-------------------------------------
五。反轉字符串
<pre name="code" class="java">* 將data中start到end之間的數字反轉
*
* @param data
* @param start
* @param end
*/
public static void reverse(char[] data, int start, int end) {
if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) {
return;
}
while (start < end) {
char tmp = data[start];
data[start] = data[end];
data[end] = tmp;
start++;
end--;
}
}
/**
* 題目一:輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字啊的順序不變。
* 爲簡單起見,標點符號和普通字母一樣處理。
*
* @param data
* @return
*/
public static char[] reverseSentence(char[] data) {
if (data == null || data.length < 1) {
return data;
}
reverse(data, 0, data.length - 1);
int start = 0;
int end = 0;
while (start < data.length) {
if (data[start] == ' ') {
start++;
end++;
} else if (end == data.length || data[end] == ' ') {
reverse(data, start, end - 1);
end++;
start = end;
} else {
end++;
}
}
return data;
六。尋找第一個不重複的元素
public class FirstNonRepeatedChar {
public static char getFirstNoRepeatChar1(String str) {
// 使用LinkedHashMap可以記住元素的插入順序
Map<Character, Integer> map = new LinkedHashMap<Character, Integer>(
str.length());
for (char c : str.toCharArray()) {
// 以字符作爲k 出現的個數作爲值
map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
}
// 遍歷MAp 找到第一個值爲1的就是找的結果
for (Entry<Character, Integer> entry : map.entrySet()) {
if (entry.getValue() == 1)
return entry.getKey();
}
throw new RuntimeException("沒有找到相關的字符");
}
public static char getFirstNoRepeatChar2(String str) {
// 保存重複的元素
Set<Character> repeating = new HashSet<Character>();
// 保存不重複的元素
List<Character> noRepeating = new ArrayList<Character>();
for (int i = 0; i < str.length(); i++) {
// 遍歷字符串
char letter = str.charAt(i);
// 集合裏已經包含了元素的時候 跳過這個元素
if (repeating.contains(letter)) {
continue;
}
// 在不重複地方集合裏包含了元素的時候刪除這個元素
if (noRepeating.contains(letter)) {
noRepeating.remove((Character) letter);
repeating.add(letter);
} else {
noRepeating.add(letter);
}
}
// 返回不重複的第一個就可以了
return noRepeating.get(0);
}
public static char getFirstNoRepeatChar3(String str) {
// 用HashMap來存儲元素和個數
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// 要是集合裏有的話 就加一
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
// 沒有的話 就存儲
map.put(c, 1);
}
}
// 遍歷集合找到值爲一的就是要找的元素
for (int j = 0; j < str.length(); j++) {
char b = str.charAt(j);
if (map.get(b) == 1)
return b;
}
throw new RuntimeException("沒有找到");
}
七。將棧變隊列
大多數人的思路是:始終維護s1作爲存儲空間,以s2作爲臨時緩衝區。
入隊時,將元素壓入s1。
出隊時,將s1的元素逐個“倒入”(彈出並壓入)s2,將s2的頂元素彈出作爲出隊元素,之後再將s2剩下的元素逐個“倒回”s1。
見下面示意圖:
2Stacks1Queue