目录


解法1: 使用堆栈
思路如下, 首先创建一个堆栈, 然后依次遍历链表, 将链表的结点依次存入堆栈, 然后新建一个链表然后依次弹出结点, 让后将此弹出的结点, 尾插到新链表的尾部
时间复杂度: O(n)
空间复杂度: O(n)
- import java.util.*;
-
- /*
- * public class ListNode {
- * int val;
- * ListNode next = null;
- * public ListNode(int val) {
- * this.val = val;
- * }
- * }
- */
-
- public class Solution {
- /**
- * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
- *
- *
- * @param head ListNode类
- * @return ListNode类
- */
- public ListNode ReverseList (ListNode head) {
- if (head == null) {
- return null;
- }
- // write code here
- Stack
stack = new Stack<>(); - ListNode newHead = new ListNode(0);
- ListNode result = newHead;
- while(head != null) {
- stack.push(head.val);
- head = head.next;
- }
- while(!stack.isEmpty()) {
- newHead.val = stack.pop();
- if (stack.isEmpty()) {
- break;
- }
- ListNode tem = new ListNode(0);
- newHead.next = tem;
- newHead = newHead.next;
- }
- return result;
-
- }
- }
解法2: 依次遍历
使用多指针的方法, 依次将结点的next赋值为他的前一个结点, 然后往后遍历.
时间复杂度: O(n)
空间复杂度: O(1)
- import java.util.*;
-
- /*
- * public class ListNode {
- * int val;
- * ListNode next = null;
- * public ListNode(int val) {
- * this.val = val;
- * }
- * }
- */
-
- public class Solution {
- /**
- * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
- *
- *
- * @param head ListNode类
- * @return ListNode类
- */
- public ListNode ReverseList (ListNode head) {
- if (head == null) {
- return null;
- }
- if (head.next == null) {
- return head;
- }
- // write code here
- ListNode l = head;
-
- ListNode center = head.next;
- ListNode r = center.next;
-
- l.next = null;
- while (center != null) {
- center.next = l;
- l = center;
- center = r;
- if (r == null) {
- return l;
- }
- r = r.next;
- }
- return null;
-
-
- }
- }
解法3: 递归
使用递归的方法来遍历这个集合, 这种方法类似于使用堆栈的方法 , 虽然代码少了很多, 但是代码的可读性缺不高, 非常锻炼玩家的思维能力.
- import java.util.*;
-
- /*
- * public class ListNode {
- * int val;
- * ListNode next = null;
- * public ListNode(int val) {
- * this.val = val;
- * }
- * }
- */
-
- public class Solution {
- /**
- * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
- *
- *
- * @param head ListNode类
- * @return ListNode类
- */
- public ListNode ReverseList (ListNode head) {
- // write code here
- if (head == null || head.next == null) {
- return head;
- }
- ListNode next = head.next;
- ListNode reverse = ReverseList(next);
- next.next = head;
- head.next = null;
- return reverse;
- }
- }
需要注意的是, 如果调用过多的递归, 会导致函数调用栈溢出的情况.


题目中给出的字符串为一个StringBuffer字符串, 他是线程安全的字符串, 同时也可以对其进行修改的字符串(我们知道java中String类是不能修改的)
在做题之前 , 我们首先应该去了解String类和StringBuffer, 和StringBuilder中提供了哪些方法供我们使用, 我将其整理在了后面的附录中, 可以点击目录查看.
我们有很多种实现的方法, 例如:
解法1: 新建一个StringBuffer字符串
新建一个StringBuffer对象, 以此扫描str, 如果不是空格, 就直接追加字符到新的字符串中, 如果是空格, 就将%20追加到新的字符串中, 然后返回他的toString方法的返回值就行.
- import java.util.*;
- public class Solution {
- public String replaceSpace(StringBuffer str) {
- StringBuffer strb = new StringBuffer();
- for(int i = 0; i < str.length(); i++) {
- char tem = str.charAt(i);
- if (tem == ' ') {
- strb.append("%20");
- } else {
- strb.append(tem);
- }
- }
- return strb.toString();
- }
- }
解法2: delete(deleteCharAt) + insert
直接遍历str, 如果是空格就先将其删除然后, 再插入%20
- import java.util.*;
- public class Solution {
- public String replaceSpace(StringBuffer str) {
- for (int i = 0; i < str.length(); i++) {
- char tem = str.charAt(i);
- if (tem == ' ') {
- str.deleteCharAt(i);
- str.insert(i,"%20");
- }
- }
- return str.toString();
- }
- }
树是一种逻辑结构,同时也是一种分层结构,

其定义结构如下:
二叉树有什么特点??

二叉树的结构代码定义:
- #include
- #include
-
- typedef char ElementType;
- typedef struct BNode {
- ElementType data;
- struct BNode* left;
- struct BNode* right;
- }BNode,*BTree;
辅助队列:
- typedef struct tag {
- BiTree p;
- struct tag* next;
- }tag_t,*ptag_t;
建树的过程:
- #define _CRT_SECURE_NO_WARNINGS 1
-
-
- #include
- #include
-
- typedef char ElementType;
- typedef struct BNode {
- ElementType data;
- struct BNode* left;
- struct BNode* right;
- }BNode,* BiTree;
-
- typedef struct tag {
- BiTree p;
- struct tag* next;
- }tag_t,*ptag_t;
-
- int main() {
- BiTree pnew; // 树的新的结点
- BiTree tree = NULL; // 树根
- ptag_t phead = NULL, ptail = NULL, listpnew = NULL, pcur = NULL;
- char c;
- while (scanf("%c", &c)) {
- if (c == '\n') {
- break;
- }
- pnew = (BiTree)calloc(1, sizeof(BNode));
- pnew->data = c;
- listpnew = (ptag_t)calloc(1, sizeof(tag_t));
- listpnew->p = pnew;
-
- if (NULL == tree) {
- tree = pnew;
- phead = listpnew;
- ptail = listpnew;
- pcur = listpnew;
- }
- else {
- ptail->next = listpnew;
- ptail = listpnew;
- if (pcur->p->left == NULL) {
- pcur->p->left = pnew;
- }
- else if (pcur->p->right == NULL ){
- pcur->p->right = pnew;
- pcur = pcur->next;
- }
-
- }
- }
-
- return 0;
- }
树是一种简单的数据结构, 面试中提到的树一般都是二叉树, 也就是一种特殊的树结构, 根节点没有父结点. ,每个结点有一到两个子节点, 树存在着好几种遍历方式, 一般有:
前中后序遍历的实现(递归实现) :
前序遍历:
以上这三种遍历方式的六种实现应该了如指掌
接下来看这三个遍历的例子:
- void preOrder(BiTree root) {
- if (root == NULL) {
- return;
- }
- printf("%c", root->data);
- preOrder(root->left);
- preOrder(root->right);
- }
-
- void inOrder(BiTree root) {
- if (root == NULL) {
- return;
- }
- inOrder(root->left);
- printf("%c", root->data);
- inOrder(root->right);
- }
-
- void lastOrder(BiTree root) {
- if (root == NULL) {
- return;
- }
- lastOrder(root->left);
- lastOrder(root->right);
- printf("%c", root->data);
- }

广度优先遍历的代码:
广度优先遍历需要借助一个辅助队列, 如下:
- void levelOrder(BiTree root) {
- SqQueue queue; // 辅助队列
- InitQueue(queue); // 初始化一个队列.
- EnQueue(queue, root); // 将根节点首先放入队列
- while (!isEmpty(queue)) {
- BiTree tem;
- DeQueue(queue,tem); // 出队一个元素.
- printf("%c", tem->data); //
- if (tem->left != NULL) { // 如果左孩子不为空, 就将左孩子入队
- EnQueue(queue, tem->left);
- }
- if (tem->right != NULL) { // 如果右孩子不为空, 就将右孩子入队
- EnQueue(queue, tem->right);
- }
- }
- }
带权路径之和:
带权路径之和为每个叶子结点的深度(路径长度)和其权值的乘积..
- #define _CRT_SECURE_NO_WARNINGS 1
-
-
- #include
- #include
-
- typedef struct BNode {
- char data;
- struct BNode* left;
- struct BNode* right;
- }BNode, * BiTree;
-
-
- typedef struct tag {
- BiTree p;
- struct tag* next;
- }tag_t, * ptag_t;
-
-
- int wpl = 0;
- int wpl_preOrder(BiTree root, int deep) {
- if (root == NULL) {
- return;
- }
- if (root->left == NULL && root->right == NULL) {
- wpl += deep * (root->data);
- }
- printf("%c", root->data);
- wpl_preOrder(root->left, deep + 1);
- wpl_preOrder(root->right, deep +1);
- return wpl;
- }
-
- int WPL(BiTree root) {
- wpl = 0;
- return wpl_preOrder(root, 0);
- }
题目链接:

实例

通过例子可以知道, 加入链表有技术个数, 那么中间结点就为中间那个数, 如果为偶数个, 那么中间结点就有两个, 例如{1,2,3,4}, 中间结点为2和3, 但是我们认为中间结点为3, 于是返回3的地址.
思路: 使用快慢指针 定义连个指针, 他们刚开始都指向头结点, 分别为slow指针和fast指针, 定义: slow指针每次只走一个结点, fast指针每次走两个结点.

经过第一次slow走一步, fast走两步:

然后再走一次, 结果如下:

此时, fast指向NULL, slow刚好指向了中间这个结点
假设现在有奇数个结点, 如下:

现在slow走一步, fast走两步
第一次:

第二次:

此时, fast的next为空时, slow指向中间结点
总结, 上面两种情况, 无论是奇数个结点还是偶数个结点, 只要fast的next为NULL或者fast本身为NULL的时候, slow就会指向中间结点.
- /**
- * struct ListNode {
- * int val;
- * struct ListNode *next;
- * };
- */
- /**
- * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
- *
- *
- * @param head ListNode类
- * @return ListNode类
- */
- struct ListNode* middleNode(struct ListNode* head ) {
- struct ListNode* slow = head;
- struct ListNode* fast = head;
- while(fast && fast->next) {
- slow = slow->next;
- fast = fast->next->next;
- }
- return slow;
- }
| Modifier and Type | Method and Description |
|---|---|
StringBuffer | append(boolean b) 将 |
StringBuffer | append(char c) 将 |
StringBuffer | append(char[] str) 将 |
StringBuffer | append(char[] str, int offset, int len) 将 |
StringBuffer | append(CharSequence s) 追加指定的 |
StringBuffer | append(CharSequence s, int start, int end) 追加指定的序列 |
StringBuffer | append(double d) 将 |
StringBuffer | append(float f) 将 |
StringBuffer | append(int i) 将 |
StringBuffer | append(long lng) 将 |
StringBuffer | append(Object obj) 追加 |
StringBuffer | append(String str) 将指定的字符串附加到此字符序列。 |
StringBuffer | append(StringBuffer sb) 将指定 |
StringBuffer | appendCodePoint(int codePoint) 将 |
int | capacity() 返回当前容量。 |
char | charAt(int index) 返回 |
int | codePointAt(int index) 返回指定索引处的字符(Unicode代码点)。 |
int | codePointBefore(int index) 返回指定索引之前的字符(Unicode代码点)。 |
int | codePointCount(int beginIndex, int endIndex) 返回此序列指定文本范围内的Unicode代码点数。 |
StringBuffer | delete(int start, int end) 删除此序列的子字符串中的字符。 |
StringBuffer | deleteCharAt(int index) 删除 |
void | ensureCapacity(int minimumCapacity) 确保容量至少等于规定的最小值。 |
void | getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 字符从该序列复制到目标字符数组 |
int | indexOf(String str) 返回指定子字符串第一次出现的字符串内的索引。 |
int | indexOf(String str, int fromIndex) 返回指定子串的第一次出现的字符串中的索引,从指定的索引开始。 |
StringBuffer | insert(int offset, boolean b) 在此序列中插入 |
StringBuffer | insert(int offset, char c) 在此序列中插入 |
StringBuffer | insert(int offset, char[] str) 在此序列中插入 |
StringBuffer | insert(int index, char[] str, int offset, int len) 在此序列中插入 |
StringBuffer | insert(int dstOffset, CharSequence s) 将指定的 |
StringBuffer | insert(int dstOffset, CharSequence s, int start, int end) 将指定的子序列 |
StringBuffer | insert(int offset, double d) 在此序列中插入 |
StringBuffer | insert(int offset, float f) 在此序列中插入 |
StringBuffer | insert(int offset, int i) 将第二个 |
StringBuffer | insert(int offset, long l) 在此序列中插入 |
StringBuffer | insert(int offset, Object obj) 将 |
StringBuffer | insert(int offset, String str) 将字符串插入到此字符序列中。 |
int | lastIndexOf(String str) 返回指定子字符串最右边出现的字符串内的索引。 |
int | lastIndexOf(String str, int fromIndex) 返回指定子字符串最后一次出现的字符串中的索引。 |
int | length() 返回长度(字符数)。 |
int | offsetByCodePoints(int index, int codePointOffset) 返回此序列中与 |
StringBuffer | replace(int start, int end, String str) 用指定的String中的字符替换此序列的子字符串中的 |
StringBuffer | reverse() 导致该字符序列被序列的相反代替。 |
void | setCharAt(int index, char ch) 指定索引处的字符设置为 |
void | setLength(int newLength) 设置字符序列的长度。 |
CharSequence | subSequence(int start, int end) 返回一个新的字符序列,该序列是该序列的子序列。 |
String | substring(int start) 返回一个新的 |
String | substring(int start, int end) 返回一个新的 |
String | toString() 返回表示此顺序中的数据的字符串。 |
void | trimToSize() 尝试减少用于字符序列的存储。 |
