一、旋转数组
描述
一个数组A中存有 n 个整数,在不允许使用另外数组的前提下,将每个整数循环向右移 M( M >=0)个位置,即将A中的数据由(A0 A1 ……AN-1 )变换为(AN-M …… AN-1 A0 A1 ……AN-M-1 )(最后 M 个数循环移至最前面的 M 个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
数据范围:0<n ≤100,0≤m ≤1000
进阶:空间复杂度 O (1),时间复杂度 O (n )
解题
如果允许使用其他数组,那么久很简单了,时间复杂度为O(n),空间复杂度也为O(n)。
但是这道题要求不允许使用额外数组 ,所以就需要用比较巧的方法解决。
最后采用的是三次旋转法(记住这个技巧就可以了,没什么别的)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution {public : vector<int > solve (int n, int m, vector<int >& a) { m = m % n; reverse (a.begin (), a.end ()); reverse (a.begin (), a.begin () + m); reverse (a.begin () + m, a.end ()); return a; }
ps:C++版本比java版本方便很多,因为有reverse函数可以直接调用
二、顺时针旋转矩阵
描述
有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵,保证N小于等于300。
示例:
输入:[[1,2,3],[4,5,6],[7,8,9]],3,返回值:[[7,4,1],[8,5,2],[9,6,3]]
代码
直接暴力交换就好,画个图很清晰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.*;public class Solution { public int [][] rotateMatrix (int [][] mat, int n) { int length = mat.length; for (int i = 0 ; i < length; ++i){ for (int j = 0 ; j < i; ++j){ int temp = mat[i][j]; mat[i][j] = mat[j][i]; mat[j][i] = temp; } } for (int i = 0 ; i < length; i++) { for (int j = 0 ; j < length/2 ; j++){ int temp = mat[i][j]; mat[i][j] = mat[i][length - j - 1 ]; mat[i][length - j - 1 ] = temp; } } return mat; } }
错误复盘
因为我刚从C++转java,所以写这段代码时最开始犯了一个很典型的错误,下面是我第一次写的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { public int [][] rotateMatrix (int [][] mat, int n) { for (int i=0 ;i<n;i++){ for (int j=i+1 ;j<n;j++){ swap (mat[i][j],mat[j][i]); } } for (int i=0 ;i<n;i++){ for (int j=0 ;j<n/2 ;j++){ swap (mat[i][j],mat[i][n-1 -j]); } } return mat; } public void swap (int a, int b) { int tmp = a; a = b; b = tmp; } }
上述代码输出时矩阵没有任何变化,原因是这段代码中存在一个常见的误解,即在 Java 中int类型传递的是值而不是引用 。在 swap
方法中,我试图通过传递参数来交换两个整数的值,但这种方式在 Java 中是不起作用的。Java 中的参数传递是按值传递的,这意味着传递给方法的是实际参数的副本,而不是参数本身。因此,即使在 swap
方法中交换了 a
和 b
的值,这只会影响方法内部的副本,而不会影响到原始数组 mat
中的值。
为了解决这个问题,可以将 swap
方法修改为接受数组索引,然后在 rotateMatrix
方法中调用这个方法来交换数组中元素的值。这样就可以实现矩阵的旋转了。
下面是修改后的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { public int [][] rotateMatrix (int [][] mat, int n) { for (int i = 0 ; i < n; i++) { for (int j = i + 1 ; j < n; j++) { swap (mat, i, j, j, i); } } for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < n / 2 ; j++) { swap (mat, i, j, i, n - 1 - j); } } return mat; } public void swap (int [][] mat, int i1, int j1, int i2, int j2) { int tmp = mat[i1][j1]; mat[i1][j1] = mat[i2][j2]; mat[i2][j2] = tmp; } }
在Java中,数组传递的是引用 。这意味着将一个数组作为参数传递给方法时,实际上传递的是数组在内存中的地址,而不是数组的副本。
总结:在 Java 中,基本数据类型(如 int、double、char 等)传递的是值,而对象类型(包括数组、类的实例等)传递的是引用。
三、设计LRU缓存结构
描述
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能:
Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
get(key):如果关键字 key 存在于缓存中,则返回key对应的value值,否则返回 -1 。
set(key, value):将记录(key, value)插入该结构,如果关键字 key 已经存在,则变更其数据值 value,如果不存在,则向缓存中插入该组 key-value ,如果key-value的数量超过capacity,弹出最久未使用的key-value
思路
一道很高频的面试题,这道题的难点是不容易想到数据结构(双向链表+哈希表 ),需要对双向链表和哈希表的操作比较了解,另外发现我写算法题习惯用C++,用JAVA完全不会写,找JAVA后端开发一定要用java刷题吗有没有人能解答我的疑惑QAQ
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <unordered_map> class Solution {public : struct Node { int key, val; Node *prev, *next; Node (int k, int v): key (k), val (v), prev (nullptr ), next (nullptr ){} }; unordered_map<int , Node*> mp; Node* L,*R; int n; Solution (int capacity){ n=capacity; L = new Node (-1 , -1 ); R = new Node (-1 , -1 ); L->next=R; R->prev=L; } int get (int key) { if (mp.count (key)){ Node *tmp = mp[key]; remove (tmp); insert (tmp); return tmp->val; } else return -1 ; } void set (int key, int value) { if (mp.count (key)){ Node* tmp = mp[key]; tmp->val = value; remove (tmp); insert (tmp); } else { Node* tmp = new Node (key,value); mp[key] = tmp; if (mp.size () > n){ Node* node = L->next; mp.erase (node->key); remove (node); insert (tmp); delete node; }else { insert (tmp); } } } void remove (Node* node) { Node* pre = node->prev; Node* nxt = node->next; pre->next = nxt; nxt->prev = pre; } void insert (Node* node) { node->prev = R->prev; R->prev->next = node; node->next = R; R->prev = node; } };
四、回文链表
题目
判断输入的链表是不是回文的
解题
这道题的知识点两个:一个是利用快慢指针找到链表中点(奇数刚好是中点,偶数的话是中点靠前一个节点),第二个是如何reverse链表,这里需要有三个指针,一个是pre,一个是cur,还有一个是curNext。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 class Solution {public : bool isPalindrome (ListNode* head) { if (head == nullptr ) return true ; ListNode* firstHalfEnd = endOfFirstHalf (head); ListNode* secondHalfStart = reverseList (firstHalfEnd->next); ListNode* p1 = head; ListNode* p2 = secondHalfStart; bool result = true ; while (result && p2 != nullptr ) { if (p1->val != p2->val) { result = false ; } p1 = p1->next; p2 = p2->next; } firstHalfEnd->next = reverseList (secondHalfStart); return result; } ListNode* endOfFirstHalf (ListNode* head) { ListNode* fast = head; ListNode* slow = head; while (fast->next != nullptr && fast->next->next != nullptr ) { fast = fast->next->next; slow = slow->next; } return slow; } ListNode* reverseList (ListNode* head) { ListNode* pre = nullptr ; ListNode* curr = head; while (curr!=nullptr ){ ListNode* nextTemp = curr->next; curr->next = pre; pre = curr; curr = nextTemp; } return pre; } };
五、八皇后问题
题目略
思路
这道题写过无数次了,但每次自己写都写不出来,在acwing看了y总的解法,代码十分优美。遂记录。
这道题的难点有三:
1、如何处理输出
2、如何遍历
3、如何判断当前行、当前列、当前对角线上是否存在皇后