1. StringBuilder/StringBuffer
Ең кең таралған және қарапайым әдіс - StringBuilder/StringBuffer пайдалану :public static String reverseString(String str) {
return new StringBuilder(str).reverse().toString();
}
Ең жақсы шешім = ең қарапайым. Java-да жолды қалай кері қайтару керек деп сұрағанда, бұл бірінші ойға келетін нәрсе. Бірақ біз алгоритмдер туралы бұрын айтқанбыз, солай емес пе? Қораптан тыс шешімдерді қарастырайық.
2. Массив шешімі
public static String reverseString(String str) {
char[] array = str.toCharArray();
String result = "";
for (int i = array.length - 1; i >= 0; i--) {
result = result + array[i];
}
return result;
}
Біз жолымызды toCharArray әдісі арқылы массивке түрлендіреміз . Осы массив арқылы оның соңынан бастап for циклін орындап , нәтиже жолына таңбаларды қосамыз.
3. charAt көмегімен шешу
public static String reverseString(String str) {
String result = "";
for (int i = 0; i < str.length(); i++) {
result = str.charAt(i) + result;
}
return result;
}
Бұл жағдайда жолды массивке бөлудің қажеті жоқ, өйткені біз әрбір таңбаны String класының әдісі - charAt арқылы шығарамыз (for циклі қайтадан кері болып табылады, бұл бізге таңбаларды ретімен кері қабылдауға мүмкіндік береді).
4. Стек көмегімен шешім
Ешкім ұзақ уақыт бойы Stack сыныбын пайдаланбайды және ол ескірген болып саналады, бірақ соған қарамастан, анықтама үшін оны қолданатын шешімді қарау пайдалы болады:public static String reverseString(String str) {
Stack<Character> stack = new Stack<>();
String result = "";
for (Character character : str.toCharArray()) {
stack.add(character);
}
while (!stack.isEmpty()) {
result = result + stack.pop();
}
return result;
}
Мұнда біз тағы да жолды массивке бөлу үшін toCharArray қолданамыз және оның барлығын жалпы типті Character бар стекке орналастырамыз . Әрі қарай, біз элементтерді стектің жоғарғы жағынан қабылдай бастаймыз. LIFO құрылымы ретінде стектің табиғатына байланысты - L ast I n First O ut (бірінші кірген, соңғы шыққан), элементтер кері қабылданады және нәтиже алынған жолда сақталады .
5. Рекурсия арқылы шешу
Кез келген алгоритм мәселесін рекурсия көмегімен шешуге болады. Мұнда да біз онсыз істей алмаймыз. Немесе оларсыз да. Өйткені, бүгін біз рекурсияны шешудің бір әдісін ғана емес, бірнешеуін қарастырамыз.-
бірінші әдіс
public static String reverseString(String str) { String rightStr; String leftStr; int length = str.length(); if (length <= 1) { return str; } leftStr = str.substring(0, length / 2); rightStr = str.substring(length / 2, length); return reverseString(rightStr) + reverseString(leftStr); }
Кіріс жолын екі тең бөлікке бөлу үшін rightStr және leftStr айнымалыларын қолданамыз. Әрі қарай, осы бөлу арқылы жолды ең кіші бөлінетін бөліктерге (1 таңба) бөлеміз. Содан кейін рекурсия таңбаларды қарама-қарсы ретпен қайтара бастайды (оң жақтағылар солға, сол жақтағылар оңға орналастырылды)
Әрбір рекурсия әдіске бірнеше рет шақыру және нәтижесінде ресурстардың айтарлықтай шығыны екенін ұмытпауымыз керек. Ал, егер біз қол жетімсіз шығу шарты бар рекурсия туралы айтатын болсақ, онда бұл шексіздікке және StackOverflowError-ке апаратын жол.
-
екінші әдіс
Мұнда бізге әдісте қосымша аргумент қажет - индекс.
Бұл әдіс іске қосылғанда оған -1 жол ұзындығы беріледі:
String str = "JavaRush forever"; System.out.println(reverseString(str, str.length()-1));
Және әдістің өзі:
public static String reverseString(String str, int index) { if(index == 0){ return str.charAt(0) + ""; } char letter = str.charAt(index); return letter + reverseString(str, index-1); }
Біздің индекс қазір қандай жол элементін қолданатынымызды көрсететін көрсеткіш ретінде қызмет етеді (және біз элементтерді соңынан қолданамыз).
Сондықтан индекс бірінші элементке жеткенде шығу шарттарын орнатамыз.
- үшінші әдіс
public static String reverseString(String str) { if (str.length() <= 1) { return str; } return reverseString(str.substring(1)) + str.charAt(0); }
Бұл әдіс негізінен рекурсивті әдістердің ішіндегі ең қарапайымы болып табылады. Есімізде, қарапайым = ең жақсы.
Әрбір іске қосу кезінде біз бірдей жолды көрсетеміз, бірақ бірінші элементсіз. Шығу шартына жеткенде (бізде бір таңба қалғанда) рекурсия ыдырай бастайды және әрбір келесі нәтижеге алдыңғы пайдаланылмаған таңба қосылады.
Әріптік индекс арқылы алынған мәндерді әдістің алдыңғы орындалу нәтижесімен қосамыз және нәтижені қайтарамыз.
6. XOR пайдалану
XOR логикалық биттік операция болып табылады. Екі айнымалы болған жағдайда, аргументтердің бірі ақиқат болса, екіншісі жалған болса ғана операцияның нәтижесі ақиқат болады.А | Б | Ы |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
(A XOR B) XOR B = A
(A XOR B) XOR A = B
Әдіс қандай болады:
public static String reverseString(String str) {
char[] arr = str.toCharArray();
int low = 0;
int high = arr.length - 1;
String result = "";
while (low < high) {
arr[low] = (char) (arr[low] ^ arr[high]);
arr[high] = (char) (arr[low] ^ arr[high]);
arr[low] = (char) (arr[low] ^ arr[high]);
low++;
high--;
}
for (int i = 0; i < arr.length; i++) {
result = result + arr[i];
}
return result;
}
Мұнда не болып жатқанын анықтайық. Біз кіріс жолынан массив жасаймыз. Біз массив бойынша өту үшін индекстерді сақтайтын төмен және жоғары екі айнымалыны жасаймыз . Тиісінше, біреуі басынан аяғына дейін жылжиды - біз оған 0 мәнін орнатамыз, екіншісі - соңынан басына дейін, біз оны arr.length - 1 орнатамыз . Біз жоғары индекс төменнен үлкен болғанша ойнайтын циклды енгіземіз . Дәл осы жерде қызықты нәрселер басталады - эксклюзивті НЕМЕСЕ пайдалану. Мысал ретінде x және y мәндерін қарастырайық . arr[жоғары] = 'x' делік ; Оның екілік codeы 1 1 1 1 0 0 0 болады Бұл уақытта arr[жоғары] = 'n'; Екілік code - 1 1 0 1 1 1 0 Циклдегі XOR операцияларында бізде не болады:
-
arr[төмен] = (char) (arr[төмен] ^ arr[жоғары]);
arr[low] = 1 1 0 1 1 1 0 arr[high] =1 1 1 1 0 0 0 arr[low] = 0 0 1 0 1 1 0
-
arr[жоғары] = (char) (arr[төмен] ^ arr[жоғары]);
arr[low] = 0 0 1 0 1 1 0 arr[high] = 1 1 1 1 0 0 0 arr[high] = 1 1 0 1 1 1 0
-
arr[төмен] = (char) (arr[төмен] ^ arr[жоғары]);
arr[low] = 0 0 1 0 1 1 0 arr[high] = 1 1 0 1 1 1 0 arr[low] = 1 1 1 1 0 0 0
GO TO FULL VERSION