記事のディレクトリ
これがLeetcodeの「回転の問題」の要約です。
最初の2つの「回転」は同じ意味を持ち、後の3つは異なる意味を持ちます
- リンクリストの回転
- アレイを回転させます
- 文字列を回転させる
- 数字を回転させる
- 画像を回転させる
1.リンクリストのローテーション
タイトル説明
リンクリストが与えられたら、リンクリストを回転させ、リンクリストの各ノードをk位置右に移動します。ここで、kは非負の数です。
例1:
入力:1-> 2-> 3-> 4-> 5-> NULL、k = 2
出力:4-> 5-> 1-> 2-> 3-> NULL
説明:
右に回転1ステップ:5 -> 1-> 2-> 3-> 4-> NULL
右に回転2ステップ:4-> 5-> 1-> 2-> 3-> NULLの
例2:
入力:0-> 1-> 2-> NULL、k = 4
出力:2-> 0-> 1-> NULL
説明:
右に回転1ステップ:2-> 0-> 1-> NULL
右に回転2ステップ: 1-> 2-> 0-> NULL
右に回転3ステップ:0-> 1-> 2-> NULL
右に回転4ステップ:2-> 0-> 1-> NULL
アイデア
実際には、リンクリストの後ろのセクションを取り出して前に置くことです。
どの段落が後ろにあるかについては、下からk番目のノードが開始して後方に移動します。リンクリストの一般的な問題は次のとおりです。最後の問題
この問題を解決するには2つの方法があります。1つは簡単に考えられます。下からk番目が正の数n-k + 1ではありません(nは1から数えてリンクリストの長さです)。
2つ目は、リンクリストの高速および低速ポインタメソッドで、 2つのポインタをkの距離に保ちます。次のポインタが最後に到達すると、前のポインタは下からk番目の位置を指します。
ここでは、最初の簡単な方法を示します。なぜ2番目のものをしないのですか?私は怠惰なので、脳が痛い、脳が痛い、コードを見ると脳が痛い...
この問題は、最後のk番目のノードの先行ノードを見つける必要があります。その後、最後のk番目のノードから切断して、ヘッドに接続することができます。
Javaコード
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
//特殊情况:链表为空或者长度为1
if(head == null || head.next == null) return head;
//计算链表长度
int len = 1;
ListNode p = head;
while(p.next!=null){
len++;
p = p.next;
}
//此时p指向尾节点
// 右移动k与右移k%len相同
k = k%len;
if(k == 0) return head;// 没有移动,直接返回
// 原问题等价于找出倒数第k个节点,然后断开插入到头部
// 倒数第k个等于正数第Len-k个(从0开始计数)
// 而要想从第k个断开,就要找到它的的前驱,就是正数第Len-k-1个(从0开始计数)
int cu = 0;
ListNode q = head;
while(cu!=len-k-1){
cu++;
q = q.next;
}
// 断开链表,并拼接
ListNode lnew = q.next;
q.next = null;
p.next = head;
return lnew;
}
}
2.アレイを回転させます
タイトル説明
配列が与えられたら、配列の要素をkの位置から右に移動します。ここで、kは非負の数です。
例1:
入力:[1,2,3,4,5,6,7]およびk = 3
出力:[5,6,7,1,2,3,4]
説明:
右に回転1ステップ:[7、 1、2,3,4,5,6-]
回転右の2つのステップ:[6,7,1,2,3,4,5]
回転右の3つのステップ:[5,6,7,1,2,3、 4]
例2:
入力:[-1、-100,3,99]およびk = 2
出力:[3,99、-1、-100]
説明:
右への回転ステップ1:[99、-1、-100,3]
右に2ステップ回転するには:[3,99、-1、-100]
説明:
できるだけ多くの解決策を考えてください。この問題を解決するには、少なくとも3つの異なる方法があります。
スペースの複雑さがO(1)のインプレースアルゴリズムを使用する必要があります。
アイデア1
回転リンクリストとは異なり、問題のスペースの複雑さはO(1)であるため、配列を半分の時間で削除して前面に配置することはできません。
したがって、最も直接的な方法は、1つずつ移動することです。
最後の要素がtempとして記録されるたびに、その前の要素が1つずつ次の要素に割り当てられ、最後にtempがnums [0]に割り当てられます。
このプロセスをk回繰り返します。つまり、k回転します。
Javaコード(1)
class Solution {
public void rotate(int[] nums, int k) {
//考虑特殊情况
if(nums == null||nums.length == 0||nums.length == 1) return;
int len = nums.length;
if(k%len == 0) return;
while(k>0){
int temp = nums[len-1];//记录最后一个元素
//从前向后移动一步
for(int i = len-1;i>0;i--){
nums[i] = nums[i-1];
}
//将第一个元素放到开头
nums[0] = temp;
k--;
}
}
}
アイデア2
最初に全体
を反転し、次に前半を反転し、
後半を反転します
Javaコード(2)
//从索引start 到end反转一个数组
private void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
class Solution {
public void rotate(int[] nums, int k) {
//考虑特殊情况
if(nums == null||nums.length == 0||nums.length == 1) return;
int len = nums.length;
if(k%len == 0) return;
reverse(nums,0,len-1);
reverse(nums,0,k-1);
reverse(nums,k,n-1);
}
}
3.弦を回転させます
タイトル説明
AとBの2つの文字列が与えられます。
Aの回転操作は、Aの左端の文字を右端に移動することです。たとえば、A = 'abcde'の場合、1回の移動後に結果は 'bcdea'になります。数回転した後、AがBになる可能性がある場合は、Trueを返します。
例1:
入力:A = 'abcde'、B = 'cdeab'
出力:true
例2:
入力:A = 'abcde'、B = 'abced'
出力:false
注:
AとBの長さは100を超えません。
アイデア
Aが回転によってBになることができる場合、2つの連続してスプライスされたAにはAのすべての回転が含まれ、Bも含まれている必要があります。
したがって、2つのAを連結し、Bが2つのAの連結された文字列にある場合はtrueを返し、そうでない場合はfalseを返します。
Javaコード
class Solution {
public boolean rotateString(String A, String B) {
//特殊情况
if(A == null&&B==null) return true;
else if(A == null &&B!=null) return false;
else if(B == null && A!=null) return false;
int lena = A.length();
int lenb = B.length();
if(lena!=lenb) return false;//长度要相等
//拼接两个A
StringBuilder sb = new StringBuilder();
sb.append(A);
sb.append(A);
//如果B在两个A的连续拼接后的字符串中,则返回true,否则,返回false
if(sb.toString().contains(B)) return true;
else return false;
}
}
4.番号を回転します
タイトル説明
数値Xを適切な数値と呼びます。各桁を1つずつ180度回転させても、Xとは異なる有効な数値を取得できます。すべての桁を回転させる必要があります。
数字の各桁が回転した後も数字である場合、その数字は有効です。0、1、および8は、回転した後もそのままです。2と5は互いに回転できます。6と9は同じですが、これらの他の番号は回転後に無効になります。
これで正の整数Nができました。1からNまでのXの数を計算してください。
例:
入力:10
出力:4
説明:
[1、10]には2、5、6、9の4つの適切な数値があります。
1と10は、回転後に変化しないため、適切な数値ではないことに注意してください。
アイデア
重要なのは、質問の意味を理解することです。「良い数字」とは何ですか?つまり、各ビットを180度回転させた後でも、それは数値であり、元のビットとは異なります。
各桁が必要なため、数字の一般的な「ビットごとのストリッピング」を実行する必要があります。この方法は難しくなく、質問でよく使用されますので、覚えておいてください。
次に、「良い数字」を判断することです。
1桁はちょうどこれらの10です:0 1 2 3 4 5 6 7 8 9
180度回転した場合、それはまだ数字です。01 2 5 6 8 9
180度回転した場合、それはまだ数ですが、元の数と同じです
。01 8が180度の回転に一致する場合、それはまだ数であり、元の数との差は2 5 69
と残りの347です。両方の条件は会っていない。
したがって、特定のビットが3 4 7である限り、その数は間違いなく適切な数ではなく、直接falseを返します。256
9が検出された場合、そのビットは2つの条件を満たすことを意味し、他のビットを判断し続けます。 。
これらの3つの数字01 8の特定の数字に遭遇した場合、その数字が「良い数字」ではないこと(他の数字は「良い数字の条件を満たす可能性がある)」でも「良い数字」でもない(良い数字)ことを示すことはできません。数字が「良い数字」の条件を満たしていない)、つまり数字の判断を変えないので、対処する必要はありません。
実際、デフォルトの数値は「適切な数値」ではありません。つまり、この状況の処理であるflag = falseです。数値の特定の桁が01 8である場合、他の桁のみが数値を「保存」するために使用され、他の桁が条件を満たす場合はフラグをtrueに変更し、そうでない場合はfalseに変更します。
Javaコード
class Solution {
public int rotatedDigits(int N) {
int count = 0;
//从1到N逐个判断
for(int i = 1;i<=N;i++){
if(isGoodNum(i)) count++;
}
return count;
}
//判断一个数字是否是“好数”
public boolean isGoodNum(int x){
boolean flag = false;
while(x!=0){
int t = x%10;
if(t == 3|| t == 4 || t== 7) return false;
else if(t == 2|| t==5||t==6||t == 9) flag = true;
x = x/10;
}
if(flag) return true;
else return false;
}
}
5.画像を回転させます
タイトル説明
n×nの場合、2次元行列は画像を表します。
画像を時計回りに90度回転させます。
説明:
画像を所定の位置で回転させる必要があります。つまり、入力された2次元行列を直接変更する必要があります。画像を回転させるために別のマトリックスを使用しないでください。
例1:
与えられた行列=
[
[1,2,3]、
[4,5,6]、
[7,8,9]
]、
入力行列を次のように回転させます。
[
[7,4,1]、
[8,5,2]、
[9,6,3]
]
例2:
与えられた行列=
[
[5、1、9,11]、
[2、4、8,10]、
[13、3、6、7]、
[15,14,12,16]
]、
回転する代わりに、入力行列がになるように:
[
[15,13、2、5]、
[14、3、4、1]、
[12、6、8、9]、
[16、7,10 、11]
]
アイデア1
時計回りに90度回転します。実際、2次元配列は最初に上下に交換され、次に対角線(\)に沿って交換されます。
Javaコード(1)
class Solution {
//交换二维数组两个点
public void swap(int[][] matrix,int x1,int y1,int x2,int y2){
int temp = matrix[x1][y1];
matrix[x1][y1] = matrix[x2][y2];
matrix[x2][y2] = temp;
}
public void rotate(int[][] matrix) {
int len = matrix.length;
//上下交换
for(int i=0;i<len/2;i++){
for(int j=0;j<len;j++){
swap(matrix,i,j,len-i-1,j);
}
}
//沿对角线交换
for(int i=0;i<len;i++){
for(int j=i;j<len;j++){
swap(matrix,i,j,j,i);
}
}
}
}
アイデア2
ループの2つの層は、1つずつ移動し、毎回4つのポイントを交換します。これは覚えにくいです、そしてそれらのインデックスは私をめまいにさせます。それでも、アイデアはシンプルで理解しやすいものです。
Javaコード(2)
class Solution {
public void rotate(int[][] matrix) {
int len = matrix.length;
for(int i=0;i<len/2;i++){
int start = i;
int end = len-i-1;
for(int j = 0;j<end-start;j++){
//交换
int temp = matrix[start][start+j];
matrix[start][start+j] = matrix[end-j][start];
matrix[end-j][start] = matrix[end][end-j];
matrix[end][end-j] = matrix[start+j][end];
matrix[start+j][end] = temp;
}
}
}