数据结构几道编程题

<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

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