1.鏈表中環的入口節點
假設x爲環前面的路程(黑色路程),a爲環入口到相遇點的路程(藍色路程,假設順時針走), c爲環的長度(藍色+橙色路程)
當快慢指針相遇的時候:
此時慢指針走的路程爲Sslow = x + m * c + a
快指針走的路程爲Sfast = x + n * c + a
2 Sslow = Sfast
2 * ( x + m*c + a ) = (x + n *c + a)
從而可以推導出:
x = (n - 2 * m )*c - a
= (n - 2 *m -1 )*c + c - a
即環前面的路程 = 數個環的長度(爲可能爲0) + c - a
什麼是c - a?這是相遇點後,環後面部分的路程。(橙色路程)
所以,我們可以讓一個指針從起點A開始走,讓一個指針從相遇點B開始繼續往後走,
2個指針速度一樣,那麼,當從原點的指針走到環入口點的時候(此時剛好走了x)
從相遇點開始走的那個指針也一定剛好到達環入口點。
所以2者會相遇,且恰好相遇在環的入口點。
最後,判斷是否有環,且找環的算法複雜度爲:
時間複雜度:O(n)
空間複雜度:O(1)
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next == null)
return null;
ListNode slow = pHead.next;
ListNode fast = pHead.next.next;
while(slow != fast)
{
if(slow.next != null && fast.next.next != null)
{
slow = slow.next;
fast = fast.next.next;
}
else{
return null;
}
}
fast = pHead;
while(slow != fast)
{
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
2.二叉樹的下一個節點
給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。
分幾種情況討論:
1.沒有右子樹和根節點
2.沒有右子樹,是其跟節點的左節點和右節點,當是右節點是還要考慮:root節點的右子樹最右節點,root左子樹最右節點。
3.有右子樹:找到其右子樹最左的節點
class TreeLinkNode{
int val;
TreeLinkNode left;
TreeLinkNode right;
TreeLinkNode next;
TreeLinkNode(int val)
{
this.val = val;
}
}
public class nextNode {
public TreeLinkNode getNextNode(TreeLinkNode root, TreeLinkNode pNode)
{
if(root == null)
return null;
if(pNode.right != null)
{
TreeLinkNode tn = pNode.right;
while(tn.left != null)
{
tn = tn.left;
}
return tn;
}
if(root.next != null)
{
TreeLinkNode p = root.next;
if(p.left == pNode)
return p;
p = pNode;
while(p.next != null)
{
p = p.next;
if(p.left == pNode)
return p;
pNode = p;
}
}
return null;
}
}
3.對稱的二叉樹
對稱是鏡像對稱。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot == null)
return true;
return isSymmetrical(pRoot.left, pRoot.right);
}
public boolean isSymmetrical(TreeNode left, TreeNode right)
{
if(left == null && right == null)
return true;
if(left == null || right == null)
return false;
if(left.val != right.val)
return false;
else
{
return isSymmetrical(left.left, right.right) && isSymmetrical(left.right, right.left);
}
}
}
3.按之字型順序打印二叉樹
請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推。
1.用兩個棧來控制。
import java.util.ArrayList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.Stack;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
Stack<TreeNode> stack1 = new Stack<TreeNode>();
Stack<TreeNode> stack2 = new Stack<TreeNode>();
if(pRoot == null)
{
return list;
}
TreeNode pNode = pRoot;
stack1.push(pRoot);
while(!stack1.isEmpty() || !stack2.isEmpty())
{
ArrayList<Integer> l = new ArrayList<Integer>();
if(!stack1.isEmpty())
{
while(!stack1.isEmpty())
{
pNode = stack1.pop();
l.add(pNode.val);
if(pNode.left != null)
stack2.push(pNode.left);
if(pNode.right != null)
stack2.push(pNode.right);
}
list.add(l);
}
else{
while(!stack2.isEmpty())
{
pNode = stack2.pop();
l.add(pNode.val);
if(pNode.right != null)
stack1.push(pNode.right);
if(pNode.left != null)
stack1.push(pNode.left);
}
list.add(l);
}
}
return list;
}
}
4.二叉搜索樹的第K個節點(第K小的節點)
1.用中序查找,用數組記錄(數值變量只起到值傳遞,數組可以實現地址傳遞)
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
TreeNode KthNode(TreeNode pRoot, int k)
{
if(pRoot == null || k <= 0)
return null;
TreeNode[] result = new TreeNode[1];
KthNode(pRoot, k, new int[1], result);
return result[0];
}
void KthNode(TreeNode root, int k, int[] count, TreeNode[] result)
{
if(root == null || result[0] != null)
{
return;
}
KthNode(root.left, k, count, result);
count[0]++;
if(count[0] == k)
{
result[0] = root;
}
KthNode(root.right, k, count, result);
}
}
5.矩陣中的路徑
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則之後不能再次進入這個格子。 例如 a b c e s f c s a d e e 這樣的3 X 4 矩陣中包含一條字符串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因爲字符串的第一個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。
1.用遞歸算法。
2.判斷邊界
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
if(rows <= 0 || cols <= 0 || matrix == null)
return false;
if(str == null || str.length == 0)
return false;
boolean[] isVisit = new boolean[cols*rows];
for(int i = 0; i < isVisit.length; i++)
isVisit[i] = false;
int index = 0;
for(int i = 0; i < rows; i++)
for(int j = 0; j < cols; j++)
{
if(isPath(matrix, rows, cols, i, j, index, str, isVisit) == true)
return true;
}
return false;
}
boolean isPath(char[] matrix, int rows, int cols, int row, int col, int index, char[] str, boolean[] isVisit)
{
if(index == str.length)
return true;
if(col < cols && col >= 0 && row < rows && row >= 0 && str[index] == matrix[row*cols+col] && isVisit[row*cols+col] == false)
{
isVisit[row*cols+col] = true;
boolean result = (isPath(matrix, rows, cols, row-1, col, index+1, str, isVisit) || isPath(matrix, rows, cols, row+1, col, index+1, str, isVisit)|| isPath(matrix, rows, cols, row, col-1, index+1, str, isVisit) || isPath(matrix, rows, cols, row, col+1, index+1, str, isVisit));
if(result == true)
return true;
isVisit[row*cols+col] = false;
}
return false;
}
}
6.機器人的運動範圍:
地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?
1.這個題目主要是要拆分函數實現的功能。
2.要有一個函數將數字轉爲和,一個函數判斷是否能進入這個格子,一個函數實現遞歸。
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
if(rows <= 0 || cols <= 0 || threshold <= 0)
return 0;
boolean[] isVisit = new boolean[rows*cols];
for(int i = 0; i < isVisit.length; i++)
isVisit[i] = false;
int count = findBlank(threshold, rows, cols, 0, 0, isVisit);
return count;
}
int findBlank(int threshold, int rows, int cols, int i, int j, boolean[] isVisit)
{
int count = 0;
boolean result = isIn(threshold, rows, cols, i, j, isVisit);
if(result == true)
{
count++;
isVisit[i*cols+j] = true;
int temp = (findBlank(threshold, rows, cols, i-1, j, isVisit) + findBlank(threshold, rows, cols, i+1, j, isVisit)
+ findBlank(threshold, rows, cols, i, j-1, isVisit)+findBlank(threshold, rows, cols, i, j+1, isVisit));
count += temp;
}
return count;
}
boolean isIn(int threshold, int rows, int cols, int i, int j, boolean isVisit[])
{
if(i >= 0 && i < rows && j >= 0 && j < cols && isVisit[i*cols+j] == false)
if(threshold >= isCan(i) + isCan(j))
return true;
return false;
}
int isCan(int number)
{
int sum = 0;
while(number != 0)
{
sum += number%10;
number /= 10;
}
return sum;
}
}