數據結構幾道編程題

<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
 

2Stacks1Queue

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章