数据结构编程题(不断更新)

记录一些数据结构的编程题好题:

1、计算二叉树深度

public class Solution {
    public int TreeDepth(TreeNode pRoot) {
        return pRoot == null ? 0 : Math.max(TreeDepth(pRoot.left), TreeDepth(pRoot.right)) + 1;
    }
}
递归递归递归!

2、逆序输出一个链表

public class Solution {
    ArrayList arrayList=new ArrayList();
    public ArrayList printListFromTailToHead(ListNode listNode) {
        if(listNode!=null){
            this.printListFromTailToHead(listNode.next);
            arrayList.add(listNode.val);
        }
        return arrayList;
    }
}  

上面的方法就是利用递归实现了栈的功能,先进后出。

自己的笨方法:

	public ArrayList printListFromTailToHead(ListNode listNode) {
		Stack res = new Stack();
		ArrayList relist = new ArrayList();
		if(listNode==null){
			return null;
		}
		while (listNode.next != null) {
			res.push(listNode.val);
			listNode = listNode.next;
		}
		res.push(listNode.val);
		while(!res.isEmpty()) {
			relist.add((Integer) res.pop());
		}
		return relist;
	}

3、知道了二叉树的前序遍历和中序遍历,复原树结构,并返回根节点

   一个前序遍历序列和一个中序遍历序列可以确定一颗唯一的二叉树。

       根据前序遍历的特点, 知前序序列(PreSequence)的首个元素(PreSequence[0])为二叉树的根(root),  然后在中序序列(InSequence)中查找此根(root),  根据中序遍历特点, 知在查找到的根(root) 前边的序列为根的左子树的中序遍历序列,  后边的序列为根的右子树的中序遍历序列。 设在中序遍历序列(InSequence)根前边有left个元素. 则在前序序列(PreSequence)中, 紧跟着根(root)的left个元素序列(即PreSequence[1...left]) 为根的左子树的前序遍历序列, 在后边的为根的右子树的前序遍历序列.而构造左子树问题其实跟构造整个二叉树问题一样,只是此时前序序列为PreSequence[1...left]), 中序序列为InSequence[0...left-1], 分别为原序列的子串, 构造右子树同样, 显然可以用递归方法解决。

import java.util.*;
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
       if(pre.length == 0||in.length == 0){
            return null;
        }
        TreeNode node = new TreeNode(pre[0]);
        for(int i = 0; i < in.length; i++){
            if(pre[0] == in[i]){
                node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), 
Arrays.copyOfRange(in, 0, i));
                node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length),
 Arrays.copyOfRange(in, i+1,in.length));
            }
        }
        return node;
    }
}

4、迭代和递归的选择

跳台阶:一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

迭代:

public int JumpFloor(int target) {

	if(target == 1 || target == 2) {
	return target;
	}

	// 第一阶和第二阶考虑过了,初始当前台阶为第三阶,向后迭代

	// 思路:当前台阶的跳法总数=当前台阶后退一阶的台阶的跳法总数+当前台阶后退二阶的台阶的跳法总数

	int jumpSum = 0;// 当前台阶的跳法总数
	int jumpSumBackStep1 = 2;// 当前台阶后退一阶的台阶的跳法总数(初始值当前台阶是第3阶)
	int jumpSumBackStep2 = 1;// 当前台阶后退二阶的台阶的跳法总数(初始值当前台阶是第3阶)
	for(int i = 3; i <= target; i++) {

	jumpSum= jumpSumBackStep1 + jumpSumBackStep2;

	jumpSumBackStep2 = jumpSumBackStep1;// 后退一阶在下一次迭代变为后退两阶

	jumpSumBackStep1 = jumpSum;                   // 当前台阶在下一次迭代变为后退一阶

	}

	return jumpSum;

	}

递归:

public class Solution {
    public int jumpFloor(int number) {
        if(number <= 0)
            return 0;
        else if(number == 1)
            return 1;
        else if(number == 2)
            return 2;
        else
            return jumpFloor(number-1) + jumpFloor(number-2);
    }
}

经常在使用递归的时候,会报错,运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大

这是由于递归会调用很多的冗余代码,造成运行时间过长。所以迭代可以使冗余代码减少,但是递归会使得程序更加清晰。

5、逆置链表

//java版链表反转
public ListNode ReverseList(ListNode head) {
         if(head==null||head.next==null){
             return head;
         }
         //反转链表
        ListNode pre=null;
        ListNode next=null;
        ListNode cur=head;
        while(cur!=null){
            next=cur.next;
            cur.next=pre;//cur.next--->pre
            pre=cur;
            cur=next;
        }
        return pre;
     }

6、快慢指针的应用

①判断单链表是否有环

public boolean hasCycle(ListNode head) {  
        if(head == null){  
            return false;  
        }  
        ListNode fast = head, slow = head;  
  
        while(fast != null && fast.next!=null){  
            slow = slow.next;  
            fast = fast.next.next;  
            if(slow == fast){  
                return true;  
            }  
        }  
        //注意循环的条件是fast不为空,并且fast.next不为空  
        //若只有一个头结点,并且头结点的next指向头结点,仍然应该返回true  
        return head.next == head;  
}  
给出一个链表,若链表中有环,给出环的入口结点,否则返回null

public ListNode detectCycle(ListNode head) {  
        //如果有环,则两者一定是在环中相遇  
        ListNode meetNode = meetNode(head);  
        if(meetNode == null){  
            return null;  
        }  
        ListNode slow = head;  
        //当两者再次相遇时,即为链表中环的入口  
        while(slow != meetNode){  
            slow = slow.next;  
            meetNode = meetNode.next;  
        }  
        return slow;  
 }  
 public ListNode meetNode(ListNode head){  
        if(head == null){  
            return null;  
        }  
        ListNode meetNode;  
        ListNode fast = head, slow = head;  
        while(fast != null && fast.next != null){  
            slow = slow.next;  
            fast = fast.next.next;  
            if(slow == fast){  
                meetNode = slow;  
                return meetNode;  
            }  
        }  
        //注意循环的条件是fast不为空,并且fast.next不为空  
        //若只有一个头结点,并且头结点的next指向头结点,仍然应该返回true  
        return head.next == head ? head : null;  
 }
相遇节点到环起始节点的距离等于链表起点到环起始节点的距离!

7、遍历一个二叉树,从上往下遍历,同级元素从左至右遍历

public class Solution {
    public ArrayList PrintFromTopToBottom(TreeNode root) {
        ArrayList list = new ArrayList();
        if(root==null){
            return list;
        }
        Queue queue = new LinkedList();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode treeNode = queue.poll();
            if (treeNode.left != null) {
                queue.offer(treeNode.left);
            }
            if (treeNode.right != null) {
                queue.offer(treeNode.right);
            }
            list.add(treeNode.val);
        }
        return list;
    }
}


8、二叉树的三种遍历方式

 /** 
     * 先序遍历 
     *  
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     *  
     * @param node 
     *            遍历的节点 
     */  
    public static void preOrderTraverse(Node node) {  
        if (node == null)  
            return;  
        System.out.print(node.data + " ");  
        preOrderTraverse(node.leftChild);  
        preOrderTraverse(node.rightChild);  
    }  
  
    /** 
     * 中序遍历 
     *  
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     *  
     * @param node 
     *            遍历的节点 
     */  
    public static void inOrderTraverse(Node node) {  
        if (node == null)  
            return;  
        inOrderTraverse(node.leftChild);  
        System.out.print(node.data + " ");  
        inOrderTraverse(node.rightChild);  
    }  
  
    /** 
     * 后序遍历 
     *  
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     *  
     * @param node 
     *            遍历的节点 
     */  
    public static void postOrderTraverse(Node node) {  
        if (node == null)  
            return;  
        postOrderTraverse(node.leftChild);  
        postOrderTraverse(node.rightChild);  
        System.out.print(node.data + " ");  
    }  

9、双栈排序:
按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中。

给定一个int[] numbers(C++中为vector<int>),其中第一个元素为栈顶,请返回排序后的栈。请注意这是一个栈,意味着排序过程中你只能访问到第一个元素。

import java.util.*;

public class TwoStacks {
    public ArrayList twoStacksSort(int[] numbers) {
    // write code here
    ArrayList result = new ArrayList<>(numbers.length);
 
    //初始化原始栈
    Stack stack = new Stack<>();
    int index = numbers.length - 1;
    for (int i = index; i >= 0; i--) {
        stack.push(numbers[i]);
    }
 
    Stack resultStack = new Stack<>();//额外的栈
    while (!stack.empty()) {
        if (resultStack.empty()) {
            resultStack.push(stack.pop());
        } else {
            int a = stack.pop();
            int b = resultStack.pop();
            int popNum = 0;
            if (a < b) {
                stack.push(b);
                while (!resultStack.empty() && a < (b = resultStack.pop())) {
                    stack.push(b);
                    popNum++;
                }
            }
            if (a >= b) {
                resultStack.push(b);
            }
            resultStack.push(a);
            while(popNum>0){
                resultStack.push(stack.pop());
                popNum--;
            }
        }
    }
 
    //返回ArrayList结果
    while (!resultStack.empty()) {
        result.add(resultStack.pop());
    }
    return result;
}
}

10、判断二叉树是否平衡

public class Balance {
    public boolean isBalance(TreeNode root) {
        // write code here
        if(root==null)
            return true;
        if(Math.abs(deepth(root.left)-deepth(root.right))>1)
            return false;
        else
            return isBalance(root.left)&isBalance(root.right);
    }
    public int deepth(TreeNode root){
        if(root==null)
            return 0;
        return Math.max(deepth(root.left),deepth(root.right))+1;
    }
}
基本思想就是算深度并进行对比。

11、删除单链表的倒数第n个节点

思路:利用间隔为n的两个指针!!Brilllllllliant!!

public ListNode removeNthFromEnd(ListNode head, int n) {
    
    ListNode start = new ListNode(0);
    ListNode slow = start, fast = start;
    slow.next = head;
    
    //Move fast in front so that the gap between slow and fast becomes n
    for(int i=1; i<=n+1; i++)   {
        fast = fast.next;
    }
    //Move fast to the end, maintaining the gap
    while(fast != null) {
        slow = slow.next;
        fast = fast.next;
    }
    //Skip the desired node
    slow.next = slow.next.next;
    return start.next;
}

12、删除单链表中重复元素

我的本办法。。。(怎么这句话老出现):

public class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode headbak = head;
        while(head != null && head.next!=null){
            if(head.val == head.next.val){
                head.next = head.next.next;
            }else{
                head = head.next;
            }
        }
        return headbak;
    }
}
递归。。。三行代码解决:

public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null)return head;
        head.next = deleteDuplicates(head.next);
        return head.val == head.next.val ? head.next : head;
}



你可能感兴趣的:(Java,数据结构,Coding,Test)